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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/742682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 23:26:15  来源:igfitidea点击:

Distinct list of objects based on an arbitrary key in LINQ

c#.netlinq

提问by Sam Saffron

I have some objects:

我有一些对象:

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

I would like to process this list in such a way that the idfield is unique, and throw away the non-unique objects (based on id).

我想以id字段唯一的方式处理此列表,并丢弃非唯一对象(基于 id)。

The best I could come up with is:

我能想到的最好的方法是:

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

Is there a nicer/better/quicker way to achieve the same result.

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

采纳答案by Sam Saffron

A very elegant and intention revealing option is to define a new extension method on IEnumerable

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

So you have:

所以你有了:

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

And ...

和 ...

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

A similar helper class can be built to compare objects. (It will need to do better null handling)

可以构建一个类似的帮助器类来比较对象。(它需要做更好的空处理)

回答by itowlson

Create an IEqualityComparer<Foo>which returns true if the id fields are the same, and pass that to the Distinct() operator.

IEqualityComparer<Foo>如果 id 字段相同,则创建返回 true 的 ,并将其传递给 Distinct() 运算符。

回答by David Leon

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

回答by chuckj

Using the Distinct()method is about 4x faster than using GroupBy() in my informal tests. For 1 million Foo's my test has Distinct() at about 0.89 seconds to make a unique array out of a non-unique array where GroupBy() takes about 3.4 seconds.

Distinct()在我的非正式测试中,使用该方法比使用 GroupBy() 快大约 4 倍。对于 100 万个 Foo,我的测试在大约 0.89 秒时使用 Distinct() 从非唯一数组中生成唯一数组,其中 GroupBy() 需要大约 3.4 秒。

My Distinct() call looks like,

我的 Distinct() 电话看起来像,

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

and FooComparerlooks like,

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

and my GroupBy()version looks like,

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

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

回答by Waldemar Ga??zinowski

Override Equals(object obj)and GetHashCode()methods:

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

and then just call Distinct():

然后只需调用Distinct()

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