在IEnumerable中合并重复元素

11

我目前有一个 IEnumerable<MyObject>,其中 MyObject 具有属性 String Namelong Value

如果在 Enumerable 中有 10 个实例的 MyObject,每个实例具有不同的名称和值,但其中一个与另一个具有相同的名称。

在 .NET (或 LINQ) 中是否有内置方法可以查找重复项,并在可能的情况下合并 Value 属性,以便在可枚举对象中只有 9 个元素,每个元素都具有唯一的 Name,其中一个具有重复项的 Value 等于它自身和重复项的总和。

到目前为止,我发现唯一的方法是遍历整个 IEnumerable,查找重复项并生成新的唯一项目的 IEnumerable,但这似乎很杂乱而且慢。

4个回答

17
你可以按名称分组项目,并将结果投射到“merged”对象中:
objects.GroupBy(o => o.Name)
       .Select(g => new MyObject { Name = g.Key, Value = g.Sum(o => o.Value) });

更新:如果不希望实例化新的 MyObject(例如,此类中有许多属性,或者您应该保留引用),则可以使用以组中第一个项目为累加器的聚合作为另一种选择:

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类型 :) - myermian
另一种变体 var dict = new ConcurrentDictionary<string, int>(); Parallel.ForEach(objects, obj => dict.AddOrUpdate(obj.Name, obj.Value, (key, oldvalue) => oldvalue + obj.Value)); - Jonas Elfström

8
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 接口并使用 Distinct 方法。如下:

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);
    }**
}

这不满足相同名称条目的值在结果中被求和的要求。 - Omaha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接