zoukankan      html  css  js  c++  java
  • C# Distinct方法的使用笔记

    引自:http://blog.csdn.net/shaopengfei/article/details/36426763 

    从C# 3.0开始提供了Distinct方法,这对于集合的使用有了更为丰富的方法,经过在网上搜索相应的资源,发现有关这方面的写的好的文章还是不少的。而且为了扩展Linq的使用不方便的地方,有一些办法非常有效。由于本人工作中的需要,有一些功能暂时没有用到那么深入,现在只把最简单的一些功能分享出来,整理出来。

    1. 简单一维集合的使用:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };  
      2. List<string> names = new List<string> { "wang", "li", "zhang", "li", "wang", "chen", "he", "wang" };  
      3.   
      4. IEnumerable<int> distinctAges = ages.Distinct();  
      5. Console.WriteLine("Distinct ages:");  
      6. foreach (int age in distinctAges)  
      7. {  
      8.      Console.WriteLine(age);  
      9. }  
      10.   
      11. var distinctNames = names.Distinct();  
      12. Console.WriteLine(" Distinct names:");  
      13. foreach (string name in distinctNames)  
      14. {  
      15.      Console.WriteLine(name);  
      16. }  
      • 在这段代码中,是最简单的Distinct()方法的使用。使用了集合接口IEnumerable,以及隐式类型var,至于这两种用法有什么区别,没有研究出来。
      • 但是如果象下面这样的代码,是错误的!

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. List<int> disAge = ages.Distinct();  
      • 正确的方法应该是:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };  
      2.   
      3. List<int> disAge = ages.Distinct().ToList();  
      4. foreach (int a in disAge)  
      5.      Console.WriteLine(a);  
      • 也就是说Distinct()方法的返回集合类型是一个接口,不是具体的集合,所以需要用一个ToList()。
    2. 自定义类的使用:

      • 首先我们看MSDN上给出的例子,先定义一个产品类:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. public class Product : IEquatable<Product>  
      2. {  
      3.     public string Name { get; set; }  
      4.     public int Code { get; set; }  
      5.   
      6.     public bool Equals(Product other)  
      7.     {  
      8.   
      9.         //Check whether the compared object is null.  
      10.         if (Object.ReferenceEquals(other, null)) return false;  
      11.   
      12.         //Check whether the compared object references the same data.  
      13.         if (Object.ReferenceEquals(this, other)) return true;  
      14.   
      15.         //Check whether the products' properties are equal.  
      16.         return Code.Equals(other.Code) && Name.Equals(other.Name);  
      17.     }  
      18.   
      19.     // If Equals() returns true for a pair of objects   
      20.     // then GetHashCode() must return the same value for these objects.  
      21.   
      22.     public override int GetHashCode()  
      23.     {  
      24.   
      25.         //Get hash code for the Name field if it is not null.  
      26.         int hashProductName = Name == null ? 0 : Name.GetHashCode();  
      27.   
      28.         //Get hash code for the Code field.  
      29.         int hashProductCode = Code.GetHashCode();  
      30.   
      31.         //Calculate the hash code for the product.  
      32.         return hashProductName ^ hashProductCode;  
      33.     }  
      34. }  
      • 在主函数里,是这样用的:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. static void Main(string[] args)  
      2. {  
      3.     Product[] products =   
      4.     {  
      5.         new Product { Name = "apple", Code = 9 },   
      6.         new Product { Name = "orange", Code = 4 },   
      7.         new Product { Name = "apple", Code = 9 },  
      8.         new Product { Name = "lemon", Code = 12 }  
      9.     };  
      10.   
      11.     //Exclude duplicates.  
      12.     IEnumerable<Product> noduplicates =  
      13.         products.Distinct();  
      14.   
      15.     foreach (var product in noduplicates)  
      16.         Console.WriteLine(product.Name + " " + product.Code);  
      17. }  
      • 这样的输出是:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. /* 
      2.     This code produces the following output: 
      3.     apple 9  
      4.     orange 4 
      5.     lemon 12 
      6. */  
      • 但是现在的问题是,如果我们把主函数里改成这样:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. static void Main(string[] args)  
      2. {  
      3.     Product[] products =   
      4.     {  
      5.         new Product { Name = "Smallapple", Code = 9 },   
      6.         new Product { Name = "orange", Code = 4 },   
      7.         new Product { Name = "Bigapple", Code = 9 },  
      8.         new Product { Name = "lemon", Code = 12 }  
      9.     };  
      10.   
      11.     //Exclude duplicates.  
      12.     IEnumerable<Product> noduplicates =  
      13.         products.Distinct();  
      14.   
      15.     foreach (var product in noduplicates)  
      16.         Console.WriteLine(product.Name + " " + product.Code);  
      17. }  
      • 这样的输出是:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. /* 
      2.     This code produces the following output: 
      3.     Smallapple 9  
      4.     orange 4 
      5.     Bigapple 9 
      6.     lemon 12 
      7. */  
      • 我们的问题是,如果想按Code来索引,想找出Code唯一的这些成员,那么这里就需要重新定义一个对Code比较的类,或者再扩展成泛型类,但是这样非常繁琐。
    3. 博客鹤冲天的改进办法(以下均转自这个博客)

      • 首先,创建一个通用比较的类,实现IEqualityComparer<T>接口:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. public class CommonEqualityComparer<T, V> : IEqualityComparer<T>  
      2. {  
      3.     private Func<T, V> keySelector;  
      4.   
      5.     public CommonEqualityComparer(Func<T, V> keySelector)  
      6.     {  
      7.         this.keySelector = keySelector;  
      8.     }  
      9.   
      10.     public bool Equals(T x, T y)  
      11.     {  
      12.         return EqualityComparer<V>.Default.Equals(keySelector(x), keySelector(y));  
      13.     }  
      14.   
      15.     public int GetHashCode(T obj)  
      16.     {  
      17.         return EqualityComparer<V>.Default.GetHashCode(keySelector(obj));  
      18.     }  
      19. }  
      • 借助上面这个类,Distinct扩展方法就可以这样写:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. public static class DistinctExtensions  
      2. {  
      3.     public static IEnumerable<T> Distinct<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)  
      4.     {  
      5.         return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));  
      6.     }  
      7. }  
      • 下面的使用就很简单了:

       

      [csharp] view plaincopy在CODE上查看代码片派生到我的代码片
       
      1. Product[] products =   
      2. {  
      3.     new Product { Name = "Smallapple", Code = 9 },   
      4.     new Product { Name = "orange", Code = 4 },   
      5.     new Product { Name = "Bigapple", Code = 9 },  
      6.     new Product { Name = "lemon", Code = 12 }  
      7. };  
      8.   
      9. var p1 = products.Distinct(p => p.Code);  
      10. foreach (Product pro in p1)  
      11.     Console.WriteLine(pro.Name + "," + pro.Code);  
      12. var p2 = products.Distinct(p => p.Name);  
      13. foreach (Product pro in p2)  
      14.     Console.WriteLine(pro.Name + "," + pro.Code);  
      • 可以看到,加上Linq表达式,可以方便的对自定义类的任意字段进行Distinct的处理。
  • 相关阅读:
    CocoaPods 的简单快速安装方法
    macOS Catalina new Shell,解决 The default interactive shell is now zsh
    Mac入门--通过homebrew下载过慢问题
    Mac下安装Android Studio
    Mac更新catalina之后有道词典闪退的解决办法
    mac系统下安装Java开发环境(一)——JDK安装
    聊天案例
    ios中常用k线
    ubuntu连接蓝牙鼠标
    image_transport
  • 原文地址:https://www.cnblogs.com/biye/p/4018963.html
Copyright © 2011-2022 走看看