Distinct()與lambda?

是的,因此我有一個可枚舉的,並但願從中得到不一樣的值。 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

我認爲那是有道理的..


#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()
相關文章
相關標籤/搜索