协慌网

登录 贡献 社区

与 lambda 不同()?

是的,所以我有一个不可估量的并希望从中获得独特的价值。

使用System.Linq ,当然有一个名为Distinct的扩展方法。在简单的情况下,可以不使用任何参数,例如:

var distinctValues = myStringList.Distinct();

很好,但是如果我有一个需要枚举的对象枚举,则唯一可用的重载是:

var distinctValues = myCustomerList.Distinct(someEqualityComparer);

相等比较器参数必须是IEqualityComparer<T>的实例。我当然可以做到这一点,但这有点冗长,而且很笨拙。

我本来希望是一个过载,它需要一个 lambda,例如 Func

var distinctValues
    = myCustomerList.Distinct((c1, c2) => c1.CustomerId == c2.CustomerId);

任何人都知道是否存在这样的扩展名或等效的解决方法?还是我错过了什么?

或者,是否有一种方法可以内联指定 IEqualityComparer(不好意思)?

更新资料

我找到了 Anders Hejlsberg 对 MSDN 论坛中有关此主题的帖子的回复。他说:

您将遇到的问题是,当两个对象比较相等时,它们必须具有相同的 GetHashCode 返回值(否则 Distinct 内部使用的哈希表将无法正常运行)。我们使用 IEqualityComparer,因为它会将 Equals 和 GetHashCode 的兼容实现打包到单个接口中。

我想这是有道理的。

答案

IEnumerable<Customer> filteredList = originalList
  .GroupBy(customer => customer.CustomerId)
  .Select(group => group.First());

像你想在我看来DistinctByMoreLINQ 。然后,您可以编写:

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;
        }
    }
}

收拾东西 。我认为像我这样来这里的大多数人都希望有最简单的解决方案, 而无需使用任何库并且具有最佳性能

(我认为按方法分组接受对于性能而言是一个过大的杀伤力。)

这是使用IEqualityComparer接口的简单扩展方法,该方法也适用于空值。

用法:

var filtered = taskList.DistinctBy(t => t.TaskExternalId).ToArray();

扩展方法代码

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