当前位置:  开发笔记 > 编程语言 > 正文

LINQ对特定属性的Distinct()

如何解决《LINQ对特定属性的Distinct()》经验,为你挑选了14个好方法。

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

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

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

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

如果LINQ不可能,那么Person在.NET 3.5 中依赖于某些属性的列表最好的方法是什么?



1> Amy B..:

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

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

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();


@ChocapicSz不.当源有多个项目时,每次抛出"Single()"和"SingleOrDefault()".在此操作中,我们预计每个组可能有多个项目.就此而言,`First()`比`FirstOrDefault()`更受欢迎,因为每个组必须至少有一个成员....除非你使用的是EntityFramework,它无法弄清楚每个组至少有一个成员和要求`FirstOrDefault()`.
我试了一下它应该改为Select(g => g.FirstOrDefault())
非常好的答案!Realllllly帮助我从Linq-to-Entities驱动的sql视图,我无法修改视图.我需要使用FirstOrDefault()而不是First() - 一切都很好.

2> Jon Skeet..:

编辑:这是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构造函数.


@ ashes999:如果你只在一个地方做这件事,那么肯定,使用`GroupBy`更简单.如果你需要在不止一个地方,那么封装意图就更清晰了(IMO).
Source to DistinctBy:http://code.google.com/p/morelinq/source/browse/MoreLinq/DistinctBy.cs
@MatthewWhited:鉴于这里没有提到`IQueryable `,我看不出它是如何相关的.我同意这不适合EF等,但在LINQ to Objects中我认为它比'GroupBy`更合适.问题的背景总是很重要.
该项目在github上移动,这里是DistinctBy的代码:https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/DistinctBy.cs

3> Chuck Rostan..:

如果您希望它看起来像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();


嗯,我的想法是查询语法和流畅的API语法就像LINQ一样,并且只是人们使用的偏好.我自己更喜欢流畅的API,所以我会考虑更多LINK-Like但我认为这是主观的

4> 小智..:

使用:

List pList = new List();
/* Fill list */

var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());

where帮助你过滤条目(可能更加复杂)和groupbyselect执行不同的功能.



5> 小智..:

我认为这就足够了:

list.Select(s => s.MyField).Distinct();


如果他需要支持他的完整对象,而不仅仅是那个特定领域呢?

6> cahit beyaz..:

首先按字段解决第一组,然后选择firstordefault项.

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



7> David Fahlan..:

您可以使用标准执行此操作Linq.ToLookup().这将为每个唯一键创建一组值.只需选择集合中的第一个项目即可

Persons.ToLookup(p => p.Id).Select(coll => coll.First());



8> Contango..:

以下代码在功能上等同于Jon Skeet的答案.

在.NET 4.5上测试,应该适用于任何早期版本的LINQ.

public static IEnumerable DistinctBy(
  this IEnumerable source, Func keySelector)
{
  HashSet seenKeys = new HashSet();
  return source.Where(element => seenKeys.Add(keySelector(element)));
}

最后,查看Jon Skeet在Google Code上的最新版DistinctBy.cs.


这给了我一个"序列没有值错误",但Skeet的答案产生了正确的结果.

9> Timothy Khou..:

我写了一篇文章,解释了如何扩展Distinct函数,以便您可以执行以下操作:

var people = new List();

people.Add(new Person(1, "a", "b"));
people.Add(new Person(2, "c", "d"));
people.Add(new Person(1, "a", "b"));

foreach (var person in people.Distinct(p => p.ID))
    // Do stuff with unique list here.

这是文章:扩展LINQ - 在不同的函数中指定属性


你的文章有一个错误,应该有一个在Distinct之后:public static IEnumerable Distinct(这个...它看起来不像它会更好地工作(很好)在一个属性上,即第一个组合和姓氏.
+1,一个小错误不足以成为downvote的理由,只是如此愚蠢,常常打字错字.我还没有看到一个适用于任何数量的属性的通用函数!我希望downvoter也在这个帖子中对所有其他答案进行了低估.但是,嘿这第二种类型是什么?我反对 !

10> mqp..:

您可以这样做(尽管不是很快):

people.Where(p => !people.Any(q => (p != q && p.Id == q.Id)));

也就是说,“选择列表中没有其他不同人且具有相同ID的所有人”。

请注意,在您的示例中,您只会选择第3个人。我不确定在前两个中如何辨别您想要哪个。



11> Andrzej Gis..:

如果您需要对多个属性使用Distinct方法,可以查看我的PowerfulExtensions库.目前它处于一个非常年轻的阶段,但你已经可以使用Distinct,Union,Intersect等方法,除了任何数量的属性;

这是你如何使用它:

using PowerfulExtensions.Linq;
...
var distinct = myArray.Distinct(x => x.A, x => x.B);



12> Vladimir Nes..:

当我们在项目中面对这样的任务时,我们定义了一个小的API来构成比较器。

因此,用例是这样的:

var wordComparer = KeyEqualityComparer.Null().
    ThenBy(item => item.Text).
    ThenBy(item => item.LangID);
...
source.Select(...).Distinct(wordComparer);

API本身如下所示:

using System;
using System.Collections;
using System.Collections.Generic;

public static class KeyEqualityComparer
{
    public static IEqualityComparer Null()
    {
        return null;
    }

    public static IEqualityComparer EqualityComparerBy(
        this IEnumerable source,
        Func keyFunc)
    {
        return new KeyEqualityComparer(keyFunc);
    }

    public static KeyEqualityComparer ThenBy(
        this IEqualityComparer equalityComparer,
        Func keyFunc)
    {
        return new KeyEqualityComparer(keyFunc, equalityComparer);
    }
}

public struct KeyEqualityComparer: IEqualityComparer
{
    public KeyEqualityComparer(
        Func keyFunc,
        IEqualityComparer equalityComparer = null)
    {
        KeyFunc = keyFunc;
        EqualityComparer = equalityComparer;
    }

    public bool Equals(T x, T y)
    {
        return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) &&
                EqualityComparer.Default.Equals(KeyFunc(x), KeyFunc(y));
    }

    public int GetHashCode(T obj)
    {
        var hash = EqualityComparer.Default.GetHashCode(KeyFunc(obj));

        if (EqualityComparer != null)
        {
            var hash2 = EqualityComparer.GetHashCode(obj);

            hash ^= (hash2 << 5) + hash2;
        }

        return hash;
    }

    public readonly Func KeyFunc;
    public readonly IEqualityComparer EqualityComparer;
}

更多详细信息,请访问我们的网站:LINQ中的IEqualityComparer



13> Joel..:

我个人使用以下课程:

public class LambdaEqualityComparer : 
    IEqualityComparer
{
    private Func _selector;

    public LambdaEqualityComparer(Func selector)
    {
        _selector = selector;
    }

    public bool Equals(TSource obj, TSource other)
    {
        return _selector(obj).Equals(_selector(other));
    }

    public int GetHashCode(TSource obj)
    {
        return _selector(obj).GetHashCode();
    }
}

然后,扩展方法:

public static IEnumerable Distinct(
    this IEnumerable source, Func selector)
{
    return source.Distinct(new LambdaEqualityComparer(selector));
}

最后,预期用途:

var dates = new List() { /* ... */ }
var distinctYears = dates.Distinct(date => date.Year);

我发现使用此方法的优点是将LambdaEqualityComparer类重新用于接受的其他方法IEqualityComparer。(哦,我把yield东西留给了原始的LINQ实现...)



14> Harry .Naeem..:

您可以使用DistinctBy()通过对象属性获取Distinct记录。只需在使用前添加以下语句即可:

使用Microsoft.Ajax.Utilities;

然后像下面这样使用它:

var listToReturn = responseList.DistinctBy(x => x.Index).ToList();

其中“索引”是我希望数据与众不同的属性。

推荐阅读
mobiledu2402852413
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有