Distinct() with lambda?

前端 未结 18 962
南旧
南旧 2020-11-22 06:04

Right, so I have an enumerable and wish to get distinct values from it.

Using System.Linq, there\'s of course an extension method called Distinct<

相关标签:
18条回答
  • 2020-11-22 06:32

    Shorthand solution

    myCustomerList.GroupBy(c => c.CustomerId, (key, c) => c.FirstOrDefault());
    
    0 讨论(0)
  • 2020-11-22 06:32

    This will do what you want but I don't know about performance:

    var distinctValues =
        from cust in myCustomerList
        group cust by cust.CustomerId
        into gcust
        select gcust.First();
    

    At least it's not verbose.

    0 讨论(0)
  • 2020-11-22 06:34

    Here's a simple extension method that does what I need...

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

    It's a shame they didn't bake a distinct method like this into the framework, but hey ho.

    0 讨论(0)
  • 2020-11-22 06:34

    Something I have used which worked well for me.

    /// <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);
        }
    }
    
    0 讨论(0)
  • 2020-11-22 06:35

    No there is no such extension method overload for this. I've found this frustrating myself in the past and as such I usually write a helper class to deal with this problem. The goal is to convert a Func<T,T,bool> to IEqualityComparer<T,T>.

    Example

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

    This allows you to write the following

    var distinctValues = myCustomerList
      .Distinct(EqualityFactory.Create((c1, c2) => c1.CustomerId == c2.CustomerId));
    
    0 讨论(0)
  • 2020-11-22 06:38

    IEnumerable lambda extension:

    public static class ListExtensions
    {        
        public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, int> hashCode)
        {
            Dictionary<int, T> hashCodeDic = new Dictionary<int, T>();
    
            list.ToList().ForEach(t => 
                {   
                    var key = hashCode(t);
                    if (!hashCodeDic.ContainsKey(key))
                        hashCodeDic.Add(key, t);
                });
    
            return hashCodeDic.Select(kvp => kvp.Value);
        }
    }
    

    Usage:

    class Employee
    {
        public string Name { get; set; }
        public int EmployeeID { get; set; }
    }
    
    //Add 5 employees to List
    List<Employee> lst = new List<Employee>();
    
    Employee e = new Employee { Name = "Shantanu", EmployeeID = 123456 };
    lst.Add(e);
    lst.Add(e);
    
    Employee e1 = new Employee { Name = "Adam Warren", EmployeeID = 823456 };
    lst.Add(e1);
    //Add a space in the Name
    Employee e2 = new Employee { Name = "Adam  Warren", EmployeeID = 823456 };
    lst.Add(e2);
    //Name is different case
    Employee e3 = new Employee { Name = "adam warren", EmployeeID = 823456 };
    lst.Add(e3);            
    
    //Distinct (without IEqalityComparer<T>) - Returns 4 employees
    var lstDistinct1 = lst.Distinct();
    
    //Lambda Extension - Return 2 employees
    var lstDistinct = lst.Distinct(employee => employee.EmployeeID.GetHashCode() ^ employee.Name.ToUpper().Replace(" ", "").GetHashCode()); 
    
    0 讨论(0)
提交回复
热议问题