Pat*_*ins 1002 c# linq distinct .net-3.5
我正在玩LINQ来了解它,但是当我没有一个简单的列表时,我无法弄清楚如何使用Distinct(一个简单的整数列表很容易做到,这不是问题).我想在对象的一个或多个属性上使用对象列表中的区别?
示例:如果对象是Person
,则使用Property Id
.如何获取所有Person并使用对象Distinct
的属性Id
?
Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"
Run Code Online (Sandbox Code Playgroud)
我怎样才能得到Person1和Person3?那可能吗?
如果LINQ不可能,那么Person
在.NET 3.5 中依赖于某些属性的列表最好的方法是什么?
Amy*_*y B 1733
如果我想根据一个或多个属性获取不同的列表,该怎么办?
简单!你想把它们分组并从小组中挑出一个胜利者.
List<Person> distinctPeople = allPeople
.GroupBy(p => p.PersonId)
.Select(g => g.First())
.ToList();
Run Code Online (Sandbox Code Playgroud)
如果要在多个属性上定义组,请按以下步骤操作:
List<Person> distinctPeople = allPeople
.GroupBy(p => new {p.PersonId, p.FavoriteColor} )
.Select(g => g.First())
.ToList();
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 1152
编辑:这是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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
因此,要仅使用Id
属性查找不同的值,您可以使用:
var query = people.DistinctBy(p => p.Id);
Run Code Online (Sandbox Code Playgroud)
要使用多个属性,可以使用匿名类型,它们适当地实现相等:
var query = people.DistinctBy(p => new { p.Id, p.Name });
Run Code Online (Sandbox Code Playgroud)
未经测试,但它应该工作(现在它至少编译).
它假设键的默认比较器 - 如果要传入相等比较器,只需将其传递给HashSet
构造函数.
Mag*_*ron 82
从 .NET 6 开始,有使用Linq 中新DistinctBy()
扩展的新解决方案,因此我们可以执行以下操作:
var distinctPersonsById = personList.DistinctBy(x => x.Id);
Run Code Online (Sandbox Code Playgroud)
方法的签名DistinctBy
:
// Returns distinct elements from a sequence according to a specified
// key selector function.
public static IEnumerable<TSource> DistinctBy<TSource, TKey> (
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector);
Run Code Online (Sandbox Code Playgroud)
Chu*_*nce 74
如果您希望它看起来像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();
Run Code Online (Sandbox Code Playgroud)
小智 67
使用:
List<Person> pList = new List<Person>();
/* Fill list */
var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)
将where
帮助你过滤条目(可能更加复杂)和groupby
和select
执行不同的功能.
小智 59
我认为这就足够了:
list.Select(s => s.MyField).Distinct();
Run Code Online (Sandbox Code Playgroud)
cah*_*yaz 37
首先按字段解决第一组,然后选择firstordefault项.
List<Person> distinctPeople = allPeople
.GroupBy(p => p.PersonId)
.Select(g => g.FirstOrDefault())
.ToList();
Run Code Online (Sandbox Code Playgroud)
Dav*_*der 24
您可以使用标准执行此操作Linq.ToLookup()
.这将为每个唯一键创建一组值.只需选择集合中的第一个项目即可
Persons.ToLookup(p => p.Id).Select(coll => coll.First());
Run Code Online (Sandbox Code Playgroud)
Con*_*ngo 17
以下代码在功能上等同于Jon Skeet的答案.
在.NET 4.5上测试,应该适用于任何早期版本的LINQ.
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> seenKeys = new HashSet<TKey>();
return source.Where(element => seenKeys.Add(keySelector(element)));
}
Run Code Online (Sandbox Code Playgroud)
最后,查看Jon Skeet在Google Code上的最新版DistinctBy.cs.
Tim*_*uri 10
我写了一篇文章,解释了如何扩展Distinct函数,以便您可以执行以下操作:
var people = new List<Person>();
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.
Run Code Online (Sandbox Code Playgroud)
这是文章:扩展LINQ - 在不同的函数中指定属性
您可以这样做(尽管不是很快):
people.Where(p => !people.Any(q => (p != q && p.Id == q.Id)));
Run Code Online (Sandbox Code Playgroud)
也就是说,“选择列表中没有其他不同人且具有相同ID的所有人”。
请注意,在您的示例中,您只会选择第3个人。我不确定在前两个中如何辨别您想要哪个。
如果您需要对多个属性使用Distinct方法,可以查看我的PowerfulExtensions库.目前它处于一个非常年轻的阶段,但你已经可以使用Distinct,Union,Intersect等方法,除了任何数量的属性;
这是你如何使用它:
using PowerfulExtensions.Linq;
...
var distinct = myArray.Distinct(x => x.A, x => x.B);
Run Code Online (Sandbox Code Playgroud)
当我们在项目中面对这样的任务时,我们定义了一个小的API来构成比较器。
因此,用例是这样的:
var wordComparer = KeyEqualityComparer.Null<Word>().
ThenBy(item => item.Text).
ThenBy(item => item.LangID);
...
source.Select(...).Distinct(wordComparer);
Run Code Online (Sandbox Code Playgroud)
API本身如下所示:
using System;
using System.Collections;
using System.Collections.Generic;
public static class KeyEqualityComparer
{
public static IEqualityComparer<T> Null<T>()
{
return null;
}
public static IEqualityComparer<T> EqualityComparerBy<T, K>(
this IEnumerable<T> source,
Func<T, K> keyFunc)
{
return new KeyEqualityComparer<T, K>(keyFunc);
}
public static KeyEqualityComparer<T, K> ThenBy<T, K>(
this IEqualityComparer<T> equalityComparer,
Func<T, K> keyFunc)
{
return new KeyEqualityComparer<T, K>(keyFunc, equalityComparer);
}
}
public struct KeyEqualityComparer<T, K>: IEqualityComparer<T>
{
public KeyEqualityComparer(
Func<T, K> keyFunc,
IEqualityComparer<T> equalityComparer = null)
{
KeyFunc = keyFunc;
EqualityComparer = equalityComparer;
}
public bool Equals(T x, T y)
{
return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) &&
EqualityComparer<K>.Default.Equals(KeyFunc(x), KeyFunc(y));
}
public int GetHashCode(T obj)
{
var hash = EqualityComparer<K>.Default.GetHashCode(KeyFunc(obj));
if (EqualityComparer != null)
{
var hash2 = EqualityComparer.GetHashCode(obj);
hash ^= (hash2 << 5) + hash2;
}
return hash;
}
public readonly Func<T, K> KeyFunc;
public readonly IEqualityComparer<T> EqualityComparer;
}
Run Code Online (Sandbox Code Playgroud)
更多详细信息,请访问我们的网站:LINQ中的IEqualityComparer。
我个人使用以下课程:
public class LambdaEqualityComparer<TSource, TDest> :
IEqualityComparer<TSource>
{
private Func<TSource, TDest> _selector;
public LambdaEqualityComparer(Func<TSource, TDest> 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();
}
}
Run Code Online (Sandbox Code Playgroud)
然后,扩展方法:
public static IEnumerable<TSource> Distinct<TSource, TCompare>(
this IEnumerable<TSource> source, Func<TSource, TCompare> selector)
{
return source.Distinct(new LambdaEqualityComparer<TSource, TCompare>(selector));
}
Run Code Online (Sandbox Code Playgroud)
最后,预期用途:
var dates = new List<DateTime>() { /* ... */ }
var distinctYears = dates.Distinct(date => date.Year);
Run Code Online (Sandbox Code Playgroud)
我发现使用此方法的优点是将LambdaEqualityComparer
类重新用于接受的其他方法IEqualityComparer
。(哦,我把yield
东西留给了原始的LINQ实现...)
您可以使用DistinctBy()通过对象属性获取Distinct记录。只需在使用前添加以下语句即可:
使用Microsoft.Ajax.Utilities;
然后像下面这样使用它:
var listToReturn = responseList.DistinctBy(x => x.Index).ToList();
Run Code Online (Sandbox Code Playgroud)
其中“索引”是我希望数据与众不同的属性。
归档时间: |
|
查看次数: |
797144 次 |
最近记录: |