LINQ中针对特定属性的Distinct()函数

40 浏览
0 Comments

LINQ中针对特定属性的Distinct()函数

我正在使用LINQ进行学习,但是我无法弄清楚如何在没有简单列表的情况下使用Distinct (简单整数列表很容易做到,这不是问题)。 如果我想在一个或多个属性上使用TElementList上的Distinct,该怎么办?

例如:如果一个对象是Person,具有属性Id。 我如何获取所有Person并使用对象的属性Id对它们进行Distinct

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

我怎么能仅获取Person1Person3? 是否有可能?

如果使用LINQ不可能,那么根据其某些属性拥有Person列表的最佳方法是什么?

admin 更改状态以发布 2023年5月25日
0
0 Comments

EDIT: 这现在是MoreLINQ的一部分。

你需要的是有效的“通过不同”功能。我不认为它已经成为LINQ的一部分,尽管很容易编写:

public static IEnumerable DistinctBy
    (this IEnumerable source, Func keySelector)
{
    HashSet seenKeys = new HashSet();
    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构造函数即可。

0
0 Comments

如果我想基于一个或多个属性获得不同的列表,该怎么办?

简单!你想要把它们分组并从组中挑选一个获胜者。

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

如果您想在多个属性上定义组,请按如下方式操作:

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

注意:某些查询提供程序无法解决每个组必须至少有一个元素,并且 First 是在那种情况下调用的适当方法。如果您发现自己在使用这样的查询提供程序,请尝试使用 FirstOrDefault 帮助您顺利进行查询。

注2:考虑使用此答案来获得与 EF Core (EF Core 6 之前) 兼容的方法。 https://stackoverflow.com/a/66529949/8155

0