基于LINQ中任意键的不同对象列表

Sam*_*ron 12 .net c# linq

我有一些对象:

class Foo {
    public Guid id;
    public string description;
}

var list = new List<Foo>();
list.Add(new Foo() { id = Guid.Empty, description = "empty" });
list.Add(new Foo() { id = Guid.Empty, description = "empty" });
list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty" });
list.Add(new Foo() { id = Guid.NewGuid(), description = "notempty2" });
Run Code Online (Sandbox Code Playgroud)

我想以这样一种方式处理这个列表,即该id字段是唯一的,并抛弃非唯一对象(基于id).

我能想到的最好的是:

list = list.GroupBy(i => i.id).Select(g=>g.First()).ToList();
Run Code Online (Sandbox Code Playgroud)

是否有更好/更好/更快的方法来实现相同的结果.

Sam*_*ron 23

一个非常优雅和意图揭示的选项是在IEnumerable上定义一个新的扩展方法

所以你有了:

list = list.Distinct(foo => foo.id).ToList();
Run Code Online (Sandbox Code Playgroud)

而......

    public static IEnumerable<T> Distinct<T,TKey>(this IEnumerable<T> list, Func<T,TKey> lookup) where TKey : struct {
        return list.Distinct(new StructEqualityComparer<T, TKey>(lookup));
    }


    class StructEqualityComparer<T,TKey> : IEqualityComparer<T> where TKey : struct {

        Func<T, TKey> lookup;

        public StructEqualityComparer(Func<T, TKey> lookup) {
            this.lookup = lookup;
        }

        public bool Equals(T x, T y) {
            return lookup(x).Equals(lookup(y));
        }

        public int GetHashCode(T obj) {
            return lookup(obj).GetHashCode();
        }
    }
Run Code Online (Sandbox Code Playgroud)

可以构建类似的辅助类来比较对象.(它需要做更好的空值处理)


chu*_*ckj 15

Distinct()在我的非正式测试中,使用该方法比使用GroupBy()快4倍.对于100万个Foo,我的测试在大约0.89秒内有Distinct(),以便在一个非独特的数组中创建一个独特的数组,其中GroupBy()需要大约3.4秒.

我的Distinct()调用看起来像,

var unique = list.Distinct(FooComparer.Instance).ToArray();
Run Code Online (Sandbox Code Playgroud)

FooComparer模样,

class FooComparer : IEqualityComparer<Foo> {
    public static readonly FooComparer Instance = new FooComparer();

    public bool Equals(Foo x, Foo y) {
        return x.id.Equals(y.id);
    }

    public int GetHashCode(Foo obj) {
        return obj.id.GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

我的GroupBy()版本看起来像,

var unique = (from l in list group l by l.id into g select g.First()).ToArray();
Run Code Online (Sandbox Code Playgroud)