關于Enumerable distinct 的學習筆記

  **Linq 的distinct 常用于對數組、集合的去重操作。**

   **一、對于數值型數組或集合去重直接Distinct()就可以。**

  new List<int>() { 1, 2, 3, 4, 3, 2 }.Distinct().ToList().ForEach(o => Console.WriteLine(o));

    **二、對于自定義類型的集合,直接Distinct往往得不到我們想要的結果**

    //例子:
     public class Food 
    {
        public int foodId { get; set; }
        public string foodName { get; set; }
        public override string ToString()
        {
            return string.Format("{0}\t{1}", foodId.ToString(), foodName.ToString());
        }
    }
      private List<Food> FoodInit()
    {
        List<Food> fl = new List<Food>();
        fl.Add(new Food { foodId = 1, foodName = "rice" });
        fl.Add(new Food { foodId = 2, foodName = "noodle" });
        fl.Add(new Food { foodId = 1, foodName = "rice" });
        return fl;
    }
    //調用:
        FoodInit().Distinct().ToList().ForEach(o => Console.WriteLine(o));
        //結果:
        //1   rice
        //2   noodle
        //1   rice

      

	  ******//解決方法:******

    **//方法1. 使用匿名類**    

   FoodInit().Select(o => new { id = o.foodId, name = o.foodName }).Distinct().ToList().ForEach(o => Console.WriteLine(o));
        //結果:
        //{ id = 1, name = rice }
        //{ id = 2, name = noodle }
        
    **//方法2. 重寫自定義類的Equals,GetHashCode方法****
  
       public class Food : IEquatable<Food>
        {
            public int foodId { get; set; }
            public string foodName { get; set; }
            public override string ToString()
            {
                return string.Format("{0}\t{1}", foodId.ToString(), foodName.ToString());
            }
        
            public  bool Equals(Food obj)
            {

                if (obj == null || GetType() != obj.GetType())
                    return false;
                Food foodItem = obj as Food;
                return (foodItem.foodId == this.foodId); //規則可以按具體需要,例如 ID  一樣則視為相等
            }
            public override int GetHashCode()
            {
                return foodId.GetHashCode(); //注意:按自定義的規則,HashCode相同,才會再去比較 Equals
            }
        }
		
		
        //調用
            FoodInit().Distinct().ToList().ForEach(o => Console.WriteLine(o));
            //結果:
            //1   rice
            //2   noodle
			
			
   **//我們可參考 MSDN 上的例子**
    public class Product : IEquatable<Product>
        {
            public string Name { get; set; }
            public int Code { get; set; }

            public bool Equals(Product other)
            {

                //Check whether the compared object is null.  
                if (Object.ReferenceEquals(other, null)) return false;

                //Check whether the compared object references the same data.  
                if (Object.ReferenceEquals(this, other)) return true;

                //Check whether the products' properties are equal.  
                return Code.Equals(other.Code) && Name.Equals(other.Name);
            }

            // If Equals() returns true for a pair of objects   
            // then GetHashCode() must return the same value for these objects.  

            public override int GetHashCode()
            {

                //Get hash code for the Name field if it is not null.  
                int hashProductName = Name == null ? 0 : Name.GetHashCode();

                //Get hash code for the Code field.  
                int hashProductCode = Code.GetHashCode();

                //Calculate the hash code for the product.  
                return hashProductName ^ hashProductCode;
            }
        }
		

     **//  方法3:  實現類的IEqualityComparer接口**
	 
      

   public class Compare : IEqualityComparer<Food>
    {
        public bool Equals(Food x, Food y)
        {
            return x.foodId == y.foodId;//可以自定义去重规则,此处将FoodId相同的就相等
        }
        public int GetHashCode(Food obj)
        {
            return obj.foodId.GetHashCode();//注意,按自定義去重規則
        }
    }
	
     //調用:
     FoodInit().Distinct(new Compare()).ToList().ForEach(s => Console.WriteLine(s.ToString()));
      //結果:
        //1   rice
        //2   noodle
						
    **//但這樣仍不方便,每個自定義類都需要去寫。我們可以寫一個通用的DISTINCT擴展方法****

 public static class DistinctExtensions
    {
        public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
        {
            private Func<T, V> keySelector;

            public CommonEqualityComparer(Func<T, V> keySelector)
            {
                this.keySelector = keySelector;
            }

            public bool Equals(T x, T y)
            {
                return EqualityComparer<V>.Default.Equals(keySelector(x), keySelector(y));
            }

            public int GetHashCode(T obj)
            {
                return EqualityComparer<V>.Default.GetHashCode(keySelector(obj));
            }
        }
        public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
        {
            return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));
        }
    }
         
		 //調用 
             FoodInit().Distinct(p => p.foodId).ToList().ForEach(o => Console.WriteLine(o));FoodInit().Distinct(p => p.foodName).ToList().ForEach(o => Console.WriteLine(o));
            //結果
            //1   rice
            //2   noodle

//網上還有一個方法
public class LambdaComparer<T> : IEqualityComparer<T>
{
 private readonly Func<T, T, bool> _lambdaComparer;
 private readonly Func<T, int> _lambdaHash;
 public LambdaComparer(Func<T, T, bool> lambdaComparer)
 : this(lambdaComparer, EqualityComparer<T>.Default.GetHashCode)
 {
 }
 public LambdaComparer(Func<T, T, bool> lambdaComparer, Func<T, int> lambdaHash)
 {
 if (lambdaComparer == null)
  throw new ArgumentNullException("lambdaComparer");
 if (lambdaHash == null)
  throw new ArgumentNullException("lambdaHash");
  _lambdaComparer = lambdaComparer;
  _lambdaHash = lambdaHash;
 }

 public bool Equals(T x, T y)
 {
 return _lambdaComparer(x, y);
 }

 public int GetHashCode(T obj)
 {
 return _lambdaHash(obj);
 }
}
很巧妙的採用了泛型委託的方式,實現只需要定義一個類實現IEqualityComparer<TSource>接口,Equals、GetHashCode的實現,由傳入的委託方法決定,接下來就簡單了

var newList3 = list.Distinct(new LambdaComparer<User>((a, b) => a.Id == b.Id && a.Name == b.Name, obj => obj.ToString().GetHashCode())).ToList();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值