Объединение повторяющихся элементов в IEnumerable
В настоящее время у меня есть IEnumerable<MyObject>
, где MyObject
имеет свойства String Name
и long Value
.
Если я должен был иметь в Enumerable, 10 экземпляров MyObject
, каждый с другим именем и значением, за исключением одного с тем же именем, что и другой.
Есть ли у .NET(или LINQ) встроенный метод, который позволит мне найти дубликат и, если возможно, объединить свойство Value
, чтобы в нем было всего 9 элементов, каждый из которых имеет отличается от Name
, и тот, у которого был дубликат, имеет Value
, равный сумме его "я" и дубликата.
До сих пор я обнаружил, что единственный способ повторить все IEnumerable
и искать дубликаты и генерировать новый IEnumerable
уникальных элементов, но это кажется неопрятным и медленным.
Ответы
Ответ 1
Вы можете группировать элементы по имени и результатам проекта в "объединенные" объекты:
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; }));
Ответ 2
list.GroupBy(e => e.Name).Select(group => new MyObject
{
Name = group.Key,
Value = group.Sum(e => e.Value)
}
)
Update:
Другой вариант:
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)});
Ответ 4
Внедрить интерфейс 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);
}**
}