是的,因此我有一个可枚举的,并但愿从中得到不一样的值。 post
使用System.Linq
,固然有一个名为Distinct
的扩展方法。 在简单的状况下,它能够在没有参数的状况下使用,例如: ui
var distinctValues = myStringList.Distinct();
好的,但若是我有一个能够指定相等性的可枚举对象,惟一可用的重载是: this
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
equality comparer参数必须是IEqualityComparer<T>
的实例。 固然,我能够作到这一点,但它有点冗长,并且颇有说服力。 spa
我所指望的是一个须要lambda的重载,好比Func <T,T,bool>: code
var distinctValues = myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
任何人都知道是否存在某些此类扩展或某些等效的解决方法? 或者我错过了什么? 对象
或者,有没有一种方法能够指定IEqualityComparer内联(embarass me)? 接口
更新 element
我找到了Anders Hejlsberg对MSDN论坛中关于这个主题的帖子的回复。 他说: get
您将要遇到的问题是,当两个对象比较相等时,它们必须具备相同的GetHashCode返回值(不然Distinct内部使用的哈希表将没法正常运行)。 咱们使用IEqualityComparer,由于它将Equals和GetHashCode的兼容实现打包到一个接口中。 hash
我认为那是有道理的..
它看起来像你想要来自MoreLINQ的 DistinctBy
。 而后你能够写:
var distinctValues = myCustomerList.DistinctBy(c => c.CustomerId);
这是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; } } }
没有这样的扩展方法重载。 我在过去发现这使人沮丧,所以我常常写一个助手类来处理这个问题。 目标是将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); } }
这容许您编写如下内容
var distinctValues = myCustomerList .Distinct(EqualityFactory.Create((c1, c2) => c1.CustomerId == c2.CustomerId));
我假设您有一个IEnumerable,而且在您的示例委托中,您但愿c1和c2引用此列表中的两个元素?
我相信你能够经过自我链接var distinctResults =来自myList中的myList join c2中的c1来实现这一点
我用过的东西对我来讲效果很好。
/// <summary> /// A class to wrap the IEqualityComparer interface into matching functions for simple implementation /// </summary> /// <typeparam name="T">The type of object to be compared</typeparam> public class MyIEqualityComparer<T> : IEqualityComparer<T> { /// <summary> /// Create a new comparer based on the given Equals and GetHashCode methods /// </summary> /// <param name="equals">The method to compute equals of two T instances</param> /// <param name="getHashCode">The method to compute a hashcode for a T instance</param> public MyIEqualityComparer(Func<T, T, bool> equals, Func<T, int> getHashCode) { if (equals == null) throw new ArgumentNullException("equals", "Equals parameter is required for all MyIEqualityComparer instances"); EqualsMethod = equals; GetHashCodeMethod = getHashCode; } /// <summary> /// Gets the method used to compute equals /// </summary> public Func<T, T, bool> EqualsMethod { get; private set; } /// <summary> /// Gets the method used to compute a hash code /// </summary> public Func<T, int> GetHashCodeMethod { get; private set; } bool IEqualityComparer<T>.Equals(T x, T y) { return EqualsMethod(x, y); } int IEqualityComparer<T>.GetHashCode(T obj) { if (GetHashCodeMethod == null) return obj.GetHashCode(); return GetHashCodeMethod(obj); } }
我在这里看到的全部解决方案都依赖于选择已经具备可比性的领域。 可是,若是须要以不一样的方式进行比较, 这里的解决方案彷佛整体上起做用,例如:
somedoubles.Distinct(new LambdaComparer<double>((x, y) => Math.Abs(x - y) < double.Epsilon)).Count()