簡體   English   中英

基於LINQ中任意鍵的不同對象列表

[英]Distinct list of objects based on an arbitrary key in 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" });

我想以這樣的方式處理這個列表,即id字段是唯一的,並拋棄非唯一對象(基於id)。

我能想到的最好的是:

list = list.GroupBy(i => i.id).Select(g=>g.First()).ToList();

是否有更好/更好/更快的方法來實現相同的結果。

一個非常優雅和意圖揭示的選項是在IEnumerable上定義一個新的擴展方法

所以你有了:

list = list.Distinct(foo => foo.id).ToList();

而......

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

可以構建類似的輔助類來比較對象。 (它需要做更好的空值處理)

在我的非正式測試中,使用Distinct()方法比使用GroupBy()快4倍。 對於100萬個Foo,我的測試在大約0.89秒內有Distinct(),以便在一個非獨特的數組中創建一個獨特的數組,其中GroupBy()需要大約3.4秒。

我的Distinct()調用看起來像,

var unique = list.Distinct(FooComparer.Instance).ToArray();

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

和我的GroupBy()版本看起來像,

var unique = (from l in list group l by l.id into g select g.First()).ToArray();

覆蓋Equals(object obj)GetHashCode()方法:

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

    public override bool Equals(object obj)
    {
        return ((Foo)obj).id == id;
    }
    public override int GetHashCode()
    {
        return id.GetHashCode();
    }
}

然后只需調用Distinct()

list = list.Distinct().ToList();

創建一個IEqualityComparer<Foo> ,如果id字段相同則返回true,並將其傳遞給Distinct()運算符。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            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" });

            var unique = from l in list
                         group l by new { l.id, l.description } into g
                         select g.Key;
            foreach (var f in unique)
                Console.WriteLine("ID={0} Description={1}", f.id,f.description);
            Console.ReadKey(); 
        }
    }

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM