我有一个班级列表

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做到这一点?

Edit

输入,

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

输出应该是,

id      value
1        a
2        c
3        d

即,如果id重复出现,result应该只取第一个出现的值。


使用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更好,还是将其实现为List、Set、Dictionary或诸如此类。


你应该有意义地重写Equals和GetHashCode,在这种情况下比较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();