2015-05-08 2 views
1

У меня есть список объектов со структурой, подобной этой: Id, OperationID, prop1, prop2 ...Найти минимальное значение с тем же идентификатором в списке

я должен удалить из списка все объект, который имеет тот же идентификатор, но имеют значение Max для OperationID .. Например, у меня есть этот экземпляр списка:

new List<MyObject> 
{ 
    new MyObject() { Id = 1, OperationId = 1, Prop1, Prop2, ... }, 
    new MyObject() { Id = 1, OperationId = 2, Prop1, Prop2, ... }, 
    new MyObject() { Id = 2, OperationId = 1, Prop1, Prop2, ... }, 
    new MyObject() { Id = 2, OperationId = 2, Prop1, Prop2, ... }, 
    new MyObject() { Id = 3, OperationId = 2, Prop1, Prop2, ... } 
} 

результат должен быть:

new List<MyObject> 
{ 
    new MyObject() { Id = 1, OperationId = 1, Prop1, Prop2, ... }, 
    new MyObject() { Id = 2, OperationId = 1, Prop1, Prop2, ... }, 
    new MyObject() { Id = 3, OperationId = 2, Prop1, Prop2, ... } 
} 

Важная вещь: мне не нужно найти только Id и operationId .. результатом должен быть весь объект!

Я попытался с Comparer, лямбда-выражения, Distinct, группирование и Select, но я не нашел решение ...

Как я могу решить?

Thanx, Simone

+0

Что делать, если вы будете есть три объекта с OperationId 1, 2, 3 для того же Id? –

+0

Итак, в основном, вы ищете, чтобы результат отличался от Id, но был минимальным доступным на основе идентификатора операции? – Clint

+0

@SergeyBerezovskiy, я должен всегда использовать объект с минимумом OperationId – Simone

ответ

1

Вы можете использовать этот запрос:

myObjects = myObjects 
    .Groupby(obj => obj.Id) 
    .Select(grp => grp.OrderBy(obj => obj.OperationId).First()) 
    .ToList(); 

Это удаляет все дубликаты в соответствии с идентификатором, и остается только самый низкий OperationId.

+0

Это моя первая попытка :) Что делать, если есть два элемента с OperationId 1 или если есть три элемента с OpeationIds 1, 2, 3? –

+0

Это позволит выбрать только отдельный идентификатор для Min OperationId. – Jack

+0

@ Сергий Березовский: Я понял, что основной целью OP является удаление дубликатов, поэтому остается только один объект. Если возможно несколько самых низких OperationId, OP должен добавить 'ThenBy' после' OrderBy'. Но логика должна быть ясной. –

1

объекты группы по идентификатору, а затем из каждой группы выбрать только те объекты, которые не имеют максимальную OperationID. Но имейте в виду, что если есть только один OperationID значение в группе, вы должны вернуть все эти объекты (контрольные minOperationId):

var result = from o in objects 
      group o by o.Id into g 
      let maxOperationId = g.Max(o => o.OperationId) 
      let minOperationId = g.Min(o => o.OperationId) 
      from o in g 
      where o.OperationId == minOperationId || o.OperationId != maxOperationId 
      select o; 

Для ввода

{ Id = 1, OperationId = 1 } 
{ Id = 1, OperationId = 2 } 
{ Id = 2, OperationId = 1 } 
{ Id = 2, OperationId = 2 } 
{ Id = 2, OperationId = 3 } 
{ Id = 3, OperationId = 1 } 
{ Id = 4, OperationId = 1 } 
{ Id = 4, OperationId = 1 } 

Выход будет

{ Id = 1, OperationId = 1 } 
{ Id = 2, OperationId = 1 } 
{ Id = 2, OperationId = 2 } 
{ Id = 3, OperationId = 1 } 
{ Id = 4, OperationId = 1 } 
{ Id = 4, OperationId = 1 } 
0

Предполагая, что ваш объект что-то вроде:

public class MyObject 
{ 
    public Int32 Id 
    { 
     get; 
     set; 
    } 

    public Int32 OperationId 
    { 
     get; 
     set; 
    } 

    public override string ToString() 
    { 
     return String.Format("{0}-{1}", this.Id, this.OperationId); 
    } 
} 

Мы можем использовать следующий LINQ запрос:

public static IEnumerable<MyObject> RemoveMaxOpIdInIdGroup(List<MyObject> items) 
{ 
    var result = items 
     // Group by id 
     .GroupBy(item => 
      item.Id) 
     // Select each group and max operation id in each group 
     .Select(group => 
      new { group, maxOperationId = group.Max(item => item.OperationId) }) 
     // From each group select the item where opid is not max for this 
     // group or if the group has only one item 
     .SelectMany(groupWithMax => 
      groupWithMax 
       .group 
       .Where(item => 
        (item.OperationId != groupWithMax.maxOperationId) || 
        (groupWithMax.group.Count() == 1))); 
    return result; 
} 

Здесь использование:

var items = new List<MyObject>() 
{ 
    new MyObject() { Id = 1, OperationId = 1}, 
    new MyObject() { Id = 1, OperationId = 2}, 
    new MyObject() { Id = 2, OperationId = 1}, 
    new MyObject() { Id = 2, OperationId = 2}, 
    new MyObject() { Id = 3, OperationId = 2} 
}; 

foreach (var obj in items) 
{ 
    Console.WriteLine(obj); 
} 

var result = RemoveMaxOpIdInIdGroup(items); 

Console.WriteLine("Result:"); 
foreach (var obj in result) 
{ 
    Console.WriteLine(obj); 
} 
0

Если вы используете MaxBy метод расширения, such as the one written by Jon Skeet, решение становится довольно простым:

var result = items.GroupBy(item => item.Id).Select(x => x.MaxBy(y => y.OperationId)); 

(Обратите внимание, что в случае нескольких элементов с Ид и OperationID, оно произвольно, который максимум один выбран.)

Пример программы:

using System; 
using System.Collections.Generic; 
using System.Diagnostics.Contracts; 
using System.Linq; 

namespace ConsoleApplication2 
{ 
    class MyObject 
    { 
     public int Id; 
     public int OperationId; 
    } 

    static class Program 
    { 
     [STAThread] 
     private static void Main() 
     { 
      IEnumerable<MyObject> items = 
       new List<MyObject> 
       { 
        new MyObject{Id = 1, OperationId = 1}, 
        new MyObject{Id = 1, OperationId = 2}, 
        new MyObject{Id = 2, OperationId = 1}, 
        new MyObject{Id = 2, OperationId = 2}, 
        new MyObject{Id = 3, OperationId = 2} 
       }; 

      var result = items.GroupBy(item => item.Id).Select(x => x.MaxBy(y => y.OperationId)); 
     } 
    } 

    public static class EnumerableMaxMinExt 
    { 
     public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector) 
     { 
      return source.MaxBy(selector, Comparer<TKey>.Default); 
     } 

     public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IComparer<TKey> comparer) 
     { 
      using (IEnumerator<TSource> sourceIterator = source.GetEnumerator()) 
      { 
       if (!sourceIterator.MoveNext()) 
       { 
        throw new InvalidOperationException("Sequence was empty"); 
       } 

       TSource max = sourceIterator.Current; 
       TKey maxKey = selector(max); 

       while (sourceIterator.MoveNext()) 
       { 
        TSource candidate = sourceIterator.Current; 
        TKey candidateProjected = selector(candidate); 

        if (comparer.Compare(candidateProjected, maxKey) > 0) 
        { 
         max = candidate; 
         maxKey = candidateProjected; 
        } 
       } 

       return max; 
      } 
     } 
    } 
} 
Смежные вопросы