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
Distinct list of objects based on an arbitrary key in LINQ
提问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 id
field 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 FooComparer
looks 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();