【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
是的,所以我有一个可枚举的,并希望从中获得不同的值。
使用System.Linq
,当然有一个名为Distinct
的扩展方法。 在简单的情况下,它可以在没有参数的情况下使用,例如:
var distinctValues = myStringList.Distinct();
好的,但如果我有一个可以指定相等性的可枚举对象,唯一可用的重载是:
var distinctValues = myCustomerList.Distinct(someEqualityComparer);
equality comparer参数必须是IEqualityComparer<T>
的实例。 当然,我可以做到这一点,但它有点冗长,而且很有说服力。
我所期望的是一个需要lambda的重载,比如Func <T,T,bool>:
var distinctValues
= myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);
任何人都知道是否存在某些此类扩展或某些等效的解决方法? 或者我错过了什么?
或者,有没有一种方法可以指定IEqualityComparer内联(embarass me)?
更新
我找到了Anders Hejlsberg对MSDN论坛中关于这个主题的帖子的回复。 他说:
您将要遇到的问题是,当两个对象比较相等时,它们必须具有相同的GetHashCode返回值(否则Distinct内部使用的哈希表将无法正常运行)。 我们使用IEqualityComparer,因为它将Equals和GetHashCode的兼容实现打包到一个接口中。
我认为那是有道理的..
#1楼
它看起来像你想要来自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;
}
}
}
#2楼
没有这样的扩展方法重载。 我在过去发现这令人沮丧,因此我经常写一个助手类来处理这个问题。 目标是将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));
#3楼
我假设您有一个IEnumerable,并且在您的示例委托中,您希望c1和c2引用此列表中的两个元素?
我相信你可以通过自我连接var distinctResults =来自myList中的myList join c2中的c1来实现这一点
#4楼
我用过的东西对我来说效果很好。
/// <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);
}
}
#5楼
我在这里看到的所有解决方案都依赖于选择已经具有可比性的领域。 但是,如果需要以不同的方式进行比较, 这里的解决方案似乎总体上起作用,例如:
somedoubles.Distinct(new LambdaComparer<double>((x, y) => Math.Abs(x - y) < double.Epsilon)).Count()
来源:oschina
链接:https://my.oschina.net/u/3797416/blog/3146412