我有一些对象:
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();
是否有更好/更好/更快的方法来实现相同的结果。
答案 0 :(得分:22)
一个非常优雅和意图揭示的选项是在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();
}
}
可以构建类似的辅助类来比较对象。 (它需要做更好的空值处理)
答案 1 :(得分:15)
在我的非正式测试中,使用Distinct()
方法比使用GroupBy()快4倍。对于100万个Foo,我的测试在大约0.89秒内有Distinct()来从一个非独特的数组中创建一个独特的数组,其中GroupBy()大约需要3.4秒。
My 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();
答案 2 :(得分:1)
创建一个IEqualityComparer<Foo>
,如果id字段相同则返回true,并将其传递给Distinct()运算符。
答案 3 :(得分:1)
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;
}
}
答案 4 :(得分:1)
覆盖等于(对象obj)和 GetHashCode()方法:
imprimir(regras); // should print all values inside "regras" but only print the last value added * "number of productions found so far".
vetor[numLinha] = regras; // should assign a list into its position in the pre-defined vector of lists at position "numLinha".
i = 0; // resets string position counter to 0 so we can reuse it for next production.
numLinha++; // increment line/rule counter.
fseek(entrada, 2, SEEK_CUR);
regras = cria_lista(); // Next lista
然后只需拨打 Distinct():
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();
}
}