使用linq选择distinct

我有一个班级列表

public class LinqTest
{
public int id { get; set; }
public string value { get; set; }
}




List<LinqTest> myList = new List<LinqTest>();
myList.Add(new LinqTest() { id = 1, value = "a" });
myList.Add(new LinqTest() { id = 1, value = "b" });
myList.Add(new LinqTest() { id = 2, value = "c" });
我需要从列表中只选择不同的id。 即,我的结果列表应该只包含

[{id=1,value="a"},{ id = 2, value = "c" }]

我如何用linq做到这一点?

编辑

输入,

id      value
1        a
1        b
2        c
3        d
3        e

输出应该是,

id      value
1        a
2        c
3        d

例如,如果id重复出现,result应该只取第一个出现项。

780970 次浏览

使用morelinq,你可以使用DistinctBy:

myList.DistinctBy(x => x.id);

否则,你可以使用一个组:

myList.GroupBy(x => x.id)
.Select(g => g.First());
myList.GroupBy(i => i.id).Select(group => group.First())
myList.GroupBy(test => test.id)
.Select(grp => grp.First());

编辑:因为将这个IEnumerable<>转换为List<>对许多人来说似乎是一个谜,你可以简单地写:

var result = myList.GroupBy(test => test.id)
.Select(grp => grp.First())
.ToList();

但是使用IEnumerable而不是IList通常会更好,因为上面的Linq是惰性求值的:它实际上不会完成所有的工作,直到迭代可枚举对象。当你调用ToList时,它实际上遍历整个枚举对象,迫使所有的工作都在前面完成。(如果你的枚举数是无限长的,可能会花一点时间。)

这个建议的另一面是,每当你枚举这样的IEnumerable时,对它的计算工作必须重新进行。因此,对于每种情况,您需要决定是使用惰性求值的IEnumerable更好,还是将其实现为ListSetDictionary或诸如此类。

你应该有意义地重写EqualsGetHashCode,在这种情况下比较ID:

public class LinqTest
{
public int id { get; set; }
public string value { get; set; }


public override bool Equals(object obj)
{
LinqTest obj2 = obj as LinqTest;
if (obj2 == null) return false;
return id == obj2.id;
}


public override int GetHashCode()
{
return id;
}
}

现在你可以使用Distinct:

List<LinqTest> uniqueIDs = myList.Distinct().ToList();