协慌网

登录 贡献 社区

LINQ 对特定属性的 Distinct()

我正在玩 LINQ 来了解它,但是当我没有一个简单的列表时,我无法弄清楚如何使用 Distinct(一个简单的整数列表很容易做到,这不是问题)。我想在对象的一个多个属性上使用对象列表中的区别

示例:如果对象是Person ,则具有 Property Id 。如何获取所有 Person 并使用对象的属性Id对它们使用Distinct

Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"

我怎样才能得到 Person1 和 Person3?那可能吗?

如果 LINQ 不可能,那么根据. NET 3.5 中的某些属性获得Person列表的最佳方法是什么?

答案

如果我想根据一个多个属性获取不同的列表, 怎么办?

简单!你想把它们分组并从小组中挑出一个胜利者。

List<Person> distinctPeople = allPeople
  .GroupBy(p => p.PersonId)
  .Select(g => g.First())
  .ToList();

如果要在多个属性上定义组,请按以下步骤操作:

List<Person> distinctPeople = allPeople
  .GroupBy(p => new {p.PersonId, p.FavoriteColor} )
  .Select(g => g.First())
  .ToList();

编辑 :这是MoreLINQ 的一部分。

你需要的是一个有效的 “明显的”。我不相信它是 LINQ 的一部分,尽管写起来相当容易:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (seenKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

因此,要仅使用Id属性查找不同的值,您可以使用:

var query = people.DistinctBy(p => p.Id);

要使用多个属性,可以使用匿名类型,它们适当地实现相等:

var query = people.DistinctBy(p => new { p.Id, p.Name });

未经测试,但它应该工作(现在它至少编译)。

它假设键的默认比较器 - 如果要传入相等比较器,只需将其传递给HashSet构造函数。

如果您希望它看起来像 LINQ 一样,您也可以使用查询语法:

var uniquePeople = from p in people
                   group p by new {p.ID} //or group by new {p.ID, p.Name, p.Whatever}
                   into mygroup
                   select mygroup.FirstOrDefault();