276

我有一个班级名单

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,结果应该只出现第一次。

4

4 回答 4

565
myList.GroupBy(test => test.id)
      .Select(grp => grp.First());

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

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

但是,与上面的 Linq 懒惰地评估IEnumerable相比,使用 往往会更好:在迭代可枚举之前,它实际上并没有完成所有工作。IList当您调用ToList它时,它实际上会遍历整个可枚举项,迫使所有工作提前完成。(如果您的可枚举项无限长,可能需要一点时间。)

这个建议的另一面是,每次你列举这样一个IEnumerable评估它的工作都必须重新完成。因此,您需要针对每种情况决定是使用惰性评估更好IEnumerable还是将其实现为List,SetDictionary诸如此类的更好。

于 2013-10-16T14:36:48.027 回答
130

使用morelinq你可以使用DistinctBy

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

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

myList.GroupBy(x => x.id)
      .Select(g => g.First());
于 2013-10-16T14:35:54.083 回答
62

您应该覆盖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();
于 2013-10-16T14:40:35.797 回答
29
myList.GroupBy(i => i.id).Select(group => group.First())
于 2013-10-16T14:36:43.103 回答