使用LINQ选择不同的结果

288

我有一个班级名单

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的重复,结果应仅取第一次出现。


3
为什么结果应该包含“a”而不是“b”? - Jodrell
1
@Jodrell: 它应该包含第一个值。 - Anoop Joshi P
4个回答

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

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

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

但通常情况下,与IList相比,使用IEnumerable更好,因为上面的Linq是惰性求值的:只有在枚举可枚举对象时才会实际执行所有的工作。当你调用ToList时,它会强制遍历整个可枚举对象,迫使所有工作一次性完成。(如果你的可枚举对象长度无限长,则可能需要花费一些时间。)

这条建议的反面是,每次枚举这样一个IEnumerable时,都需要重新评估它。因此,您需要为每种情况决定是更好地使用惰性求值的IEnumerable还是将其转换为ListSetDictionary等实现。


8
请注意:除非您将其转换回列表,否则此方法将无法正常工作。GroupBy().Select(First()) 将生成一个 IEnumerable,您将会遇到转换错误。请使用以下代码: myList.GroupBy(test => test.id) .Select(group => group.First()).ToList(); - maplemale
2
你必须定义newList。然后将结果设置为这个newList。否则分组无法正常工作。这对我有用。 'List<LinqTest> newList = new List<LinqTest>(); newList = myList.GroupBy(test => test.id) .Select(group => group.First());' - yunus
3
嗨,尤努斯。感谢您的小评论。我能够通过使用你的代码并更改列表内容来使我的IEnumerable工作: IEnumerable rows = from c in dc.EDI_RAW_TCRs where c.Batch_ID == 20830 select c; IEnumerable raws = rows; raws = rows.GroupBy(t => t.LabID) .Select(group => group.First()); - JustJohn
3
在C#中,需要使用.FirstOrDefault()而不是.First()。 - Sruit A.Suk
1
@Sruit,不,它没有。 - Paul Ruane
3
@Sruit,C#并不要求这样做,但是如果你在仓储(repository)中尝试这样做的话,EF可能会让你头疼。 - FailedUnitTest

142

使用 morelinq,你可以使用 DistinctBy

myList.DistinctBy(x => x.id);
否则,您可以使用一个组:
myList.GroupBy(x => x.id)
      .Select(g => g.First());

2
不知道这个包,绝对是需要的好东西。 - Jay
4
哪个更快? - rollsch
1
@MarkWardell:在.NET中从未存在过“DistinctBy”。正如我在我的答案中所写的那样,您需要使用morelinq来获得该功能。 - Daniel Hilgarth
非常感谢您。这是一个非常有趣的软件包。 - Theotonio

63

在这种情况下,您应该有意义地重写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();

30
myList.GroupBy(i => i.id).Select(group => group.First())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接