Tor*_*gen 714 c# lambda extension-methods c#-3.0
是的,所以我有一个可枚举的,并希望从中获得不同的值.
使用System.Linq,当然有一个名为的扩展方法Distinct.在简单的情况下,它可以在没有参数的情况下使用,例如:
var distinctValues = myStringList.Distinct();
Run Code Online (Sandbox Code Playgroud)
好的,但如果我有一个可以指定相等性的可枚举对象,唯一可用的重载是:
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
Run Code Online (Sandbox Code Playgroud)
equality comparer参数必须是.的实例IEqualityComparer<T>.当然,我可以做到这一点,但它有点冗长,而且很有说服力.
我所期望的是一个需要lambda的重载,比如Func <T,T,bool>:
var distinctValues
= myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
Run Code Online (Sandbox Code Playgroud)
任何人都知道是否存在某些此类扩展或某些等效的解决方法?或者我错过了什么?
或者,有没有一种方法可以指定IEqualityComparer内联(embarass me)?
更新
我找到了Anders Hejlsberg对MSDN论坛中关于这个主题的帖子的回复.他说:
您将遇到的问题是,当两个对象比较相等时,它们必须具有相同的GetHashCode返回值(否则Distinct内部使用的哈希表将无法正常运行).我们使用IEqualityComparer,因为它将Equals和GetHashCode的兼容实现打包到一个接口中.
我认为那是有道理的..
小智 982
IEnumerable<Customer> filteredList = originalList
.GroupBy(customer => customer.CustomerId)
.Select(group => group.First());
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 478
它看起来像你想要的更多DistinctBy来自MoreLINQ.然后你可以写:
var distinctValues = myCustomerList.DistinctBy(c => c.CustomerId);
Run Code Online (Sandbox Code Playgroud)
这是一个简化版本DistinctBy(没有无效检查,没有指定自己的密钥比较器的选项):
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
HashSet<TKey> knownKeys = new HashSet<TKey>();
foreach (TSource element in source)
{
if (knownKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ane*_*lou 37
总结一下.我想像我这样来到这里的大多数人都希望在不使用任何库和最佳性能的情况下实现最简单的解决方案.
(对我而言,接受的方法对我而言,我认为在表现方面是一种矫枉过正.)
这是一个使用IEqualityComparer接口的简单扩展方法,该接口也适用于空值.
用法:
var filtered = taskList.DistinctBy(t => t.TaskExternalId).ToArray();
Run Code Online (Sandbox Code Playgroud)
扩展方法代码
public static class LinqExtensions
{
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> property)
{
GeneralPropertyComparer<T, TKey> comparer = new GeneralPropertyComparer<T,TKey>(property);
return items.Distinct(comparer);
}
}
public class GeneralPropertyComparer<T,TKey> : IEqualityComparer<T>
{
private Func<T, TKey> expr { get; set; }
public GeneralPropertyComparer (Func<T, TKey> expr)
{
this.expr = expr;
}
public bool Equals(T left, T right)
{
var leftProp = expr.Invoke(left);
var rightProp = expr.Invoke(right);
if (leftProp == null && rightProp == null)
return true;
else if (leftProp == null ^ rightProp == null)
return false;
else
return leftProp.Equals(rightProp);
}
public int GetHashCode(T obj)
{
var prop = expr.Invoke(obj);
return (prop==null)? 0:prop.GetHashCode();
}
}
Run Code Online (Sandbox Code Playgroud)
Vij*_*mal 20
从 .NET 6 或更高版本开始,有一个新的内置方法Enumerable.DistinctBy可以实现此目的。
var distinctValues = myCustomerList.DistinctBy(c => c.CustomerId);
// With IEqualityComparer
var distinctValues = myCustomerList.DistinctBy(c => c.CustomerId, someEqualityComparer);
Run Code Online (Sandbox Code Playgroud)
Jar*_*Par 19
没有这样的扩展方法重载.我在过去发现这令人沮丧,因此我经常写一个助手类来处理这个问题.目标是将a转换Func<T,T,bool>为IEqualityComparer<T,T>.
例
public class EqualityFactory {
private sealed class Impl<T> : IEqualityComparer<T,T> {
private Func<T,T,bool> m_del;
private IEqualityComparer<T> m_comp;
public Impl(Func<T,T,bool> del) {
m_del = del;
m_comp = EqualityComparer<T>.Default;
}
public bool Equals(T left, T right) {
return m_del(left, right);
}
public int GetHashCode(T value) {
return m_comp.GetHashCode(value);
}
}
public static IEqualityComparer<T,T> Create<T>(Func<T,T,bool> del) {
return new Impl<T>(del);
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您编写以下内容
var distinctValues = myCustomerList
.Distinct(EqualityFactory.Create((c1, c2) => c1.CustomerId == c2.CustomerId));
Run Code Online (Sandbox Code Playgroud)
Ara*_*RRK 18
速记解决方案
myCustomerList.GroupBy(c => c.CustomerId, (key, c) => c.FirstOrDefault());
Run Code Online (Sandbox Code Playgroud)
小智 12
这将做你想要的,但我不知道性能:
var distinctValues =
from cust in myCustomerList
group cust by cust.CustomerId
into gcust
select gcust.First();
Run Code Online (Sandbox Code Playgroud)
至少它不是冗长的.
Dav*_*and 12
这是一个简单的扩展方法,可以满足我的需求......
public static class EnumerableExtensions
{
public static IEnumerable<TKey> Distinct<T, TKey>(this IEnumerable<T> source, Func<T, TKey> selector)
{
return source.GroupBy(selector).Select(x => x.Key);
}
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是,他们没有将这样一个独特的方法烘焙到框架中,但是嘿嘿.
| 归档时间: |
|
| 查看次数: |
371410 次 |
| 最近记录: |