2013-09-09 4 views
11

В настоящее время у меня есть IEnumerable<MyObject>, где MyObject имеет свойства String Name и long Value.Слияние дублирующих элементов внутри IEnumerable

Если бы я должен был иметь внутри Enumerable, 10 экземпляров MyObject, каждый из которых имеет другое имя и значение, за исключением одного с тем же именем, что и другое.

Имеет ли .NET (или LINQ) встроенный метод, который позволит мне найти дубликат и, если возможно, объединить свойство Value, чтобы в нем было всего 9 элементов, каждый из которых отличался Name и тот, у которого был дубликат, есть Value, который равен сумме его «я» и «дубликат».

До сих пор я нашел, что единственный способ перебрать по всему IEnumerable и искать дубликаты и генерировать новый IEnumerable уникальных предметов, но это кажется неопрятным и медленным.

ответ

16

Вы можете сгруппировать элементы по названию и проектных результатов для «слиты» объектов:

objects.GroupBy(o => o.Name) 
     .Select(g => new MyObject { Name = g.Key, Value = g.Sum(o => o.Value) }); 

UPDATE: Еще один вариант, если новый MyObject конкретизации нежелателен (например, у вас есть много свойств в этом классе, или вы должны ссылки Хранителей), то вы можете использовать агрегацию с первым элементом в группе в качестве аккумулятора:

objects.GroupBy(o => o.Name) 
     .Select(g => g.Skip(1).Aggregate(
         g.First(), (a, o) => { a.Value += o.Value; return a; })); 
+1

Стоит отметить, что один, вероятно, следует указать тип 'StringComparer' использовать :) –

+0

еще один вариант' уаг Dict = новый ConcurrentDictionary (); Parallel.ForEach (объекты, obj => dict.AddOrUpdate (obj.Name, obj.Value, (ключ, oldvalue) => oldvalue + obj.Value)); ' –

7
list.GroupBy(e => e.Name).Select(group => new MyObject 
    { 
     Name = group.Key, 
     Value = group.Sum(e => e.Value) 
    } 
) 

обновления:
Другой вариант:

list.GroupBy(
    e => e.Name, 
    e => e, 
    (name, group) => group.Aggregate((result, e) => 
     { 
      result.Value += e.Value; 
      return result; 
     } 
    ) 
) 
3

Я не знаю ни одного решения метод, но как насчет:

set.GroupBy(g=>g.Name).Select(g=> new MyObject{Name=g.Key, Value=g.Sum(i=>i.Value)}); 
1

реализует интерфейс IEquatable и использовать Ditinct метод. Как следует:

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     var items = new List<MyClass> 
        { 
         new MyClass 
         { 
          Name = "Name1", 
          Value = 50 
         }, 
         new MyClass 
         { 
          Name = "Name2", 
          Value = 20 
         }, 
         new MyClass 
         { 
          Name = "Name3", 
          Value = 50 
         } 
        }; 
     var distinct = items.Distinct().ToList(); 
    } 
} 

internal class MyClass : **IEquatable<MyClass>** 
{ 
    public String Name { get; set; } 
    public int Value { get; set; } 

    **public bool Equals(MyClass other) 
    { 
     if (ReferenceEquals(null, other)) 
      return false; 
     if (ReferenceEquals(this, other)) 
      return true; 
     return this.Value == other.Value; 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) 
      return false; 
     if (ReferenceEquals(this, obj)) 
      return true; 
     if (obj.GetType() != this.GetType()) 
      return false; 
     return this.Equals((MyClass)obj); 
    } 

    public override int GetHashCode() 
    { 
     return this.Value; 
    } 

    public static bool operator ==(MyClass left, MyClass right) 
    { 
     return Equals(left, right); 
    } 

    public static bool operator !=(MyClass left, MyClass right) 
    { 
     return !Equals(left, right); 
    }** 
} 
+0

Это не удовлетворяет требованию, чтобы значения записей с в результате суммируются идентичные имена. – Omaha