zoukankan      html  css  js  c++  java
  • linq中的Distinct的使用(附带IComparable和IComparer的复习和使用)

    Distinct 的使用,说指简单,也比较复杂,因为它拓展的东西比较多

    先看本类型的使用:

    简单示例:

                List<int> intList = new List<int>() {1,1,2,2,3,3};
                var result=intList.Distinct();
    
                //能得到我们想要的效果:1 2 3
    
                List<string> strList = new List<string>() { "1", "1", "2", "2", "3", "3"};
                var resultList = intList.Distinct();
    
                //能得到我们想要的效果:"1"  "2"  "3"

    But 当在我们引用对象的时候,效果就有点不一样了!

     public class Person
        {
            public int ID { get; set; }
    
            public string Name { get; set; }
        }
    
        class Program
        {
    
    
            static void Main(string[] args)
            {
    
                List<Person> list = new List<Person>()
                {
                    new Person() { ID=1,Name="jack" },
                    new Person() { ID=1,Name="jack" },
                    new Person() { ID=2,Name="tom" },
                    new Person() { ID=2,Name="tom" }
                };
                var result = list.Distinct();
                Console.Read();
    
            }
        }

    结果却是这样的:

    说明,没有起到我们想要的效果;

    原因是,它重复判断定的对象是我们的 引用!

    看下面的这个....

    然后如何得到我们想要的去重复效果呢?

    Distinct方法还有另一个重载:

    //通过使用指定的 System.Collections.Generic.IEqualityComparer<T> 对值进行比较

    //返回序列中的非重复元素。

    public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source, 

     IEqualityComparer<TSource> comparer);

     该重载接收一个IEqualityComparer的参数。

    假设要按Id来筛选;(需要实现两个方法)

    实现代码如下:定义个去除重复的标准)

    public class PersonComparer : IEqualityComparer<Person>
        {
    
            public bool Equals(Person x,Person y)
            {
                if (x == null)
                    return y == null;
                return x.ID == y.ID;
            }
    
            public int GetHashCode(Person obj)
            {
                if (obj == null)
                    return 0;
                return obj.ID.GetHashCode();
            }
    
        }

    使用方法:

    var result = list.Distinct(new PersonComparer());

    结果:

    要是现在我想用name来作为比较的基准呢?

    实现代码:

        public class PropertyComparer<T> : IEqualityComparer<T>
        {
            private PropertyInfo _PropertyInfo;  //这个要用到反射
    
            //写成一个较为通用的方法
            public PropertyComparer(string propertyName)
            {
                _PropertyInfo = typeof(T).GetProperty(propertyName,BindingFlags.GetProperty|BindingFlags.Instance|BindingFlags.Public);
                if (_PropertyInfo == null)
                {
                    throw new ArgumentException(string.Format("{0} is not a property of type {1}.",
                    propertyName, typeof(T)));
                }
            }
    
            public bool Equals(T x,T y)
            {
                object xValue = _PropertyInfo.GetValue(x,null);
                object yValue = _PropertyInfo.GetValue(x, null);
                if (xValue == null)
                    return yValue == null;
                return xValue.Equals(yValue);
            }
    
            public int GetHashCode(T obj)
            {
                object propertyValue = _PropertyInfo.GetValue(obj,null);
                if (propertyValue == null)
                {
                    return 0;
                }
                else
                {
                    return propertyValue.GetHashCode();
                }
            }
        }

    具体使用:

      var result = list.Distinct(new PropertyComparer<Person>("Name"));

      通过上面的两个示例之后,我们又了一些基本的认识;

      写到这里,我们可以看看我们的静态扩展方法的使用滴啊;

    然后,你以为就完了,太年轻..............

    去除重复的值,然后留下一种的一个值,你以为只有我们的distinct 可以做到呀;

    当然少不了的我们的groupby的使用滴呀;

    来自我们Stack Overflow的答案:

    效果还是挺好得呀

     还有这个方法;我们先把方法贴出来,然后我们再洗洗的品味;

    //在进行比价之前,我们先复习一些基础的东西;IComparable 进行排序的比较; 

    先来看一个基本的:

                int a = 12;
                Console.WriteLine(a.CompareTo(16)); //-1
                Console.WriteLine(a.CompareTo(12)); //0
                Console.WriteLine(a.CompareTo(1)); //1

    以下,我们主要使用:Sort方法要 通过对象去继承IComparable接口来实现排序

      public class Student : IComparable
        {
    
            public string Name { get; set; }
    
            public int Age { get; set; }
    
            //接口中定义的方法;int CompareTo(object obj);; 然后我们来实现自定义的比较低呀
    
            public int CompareTo(object obj) 
            {
                var s = obj as Student;
                if (Age > s.Age)
                {
                    return 1;
                }else if (Age == s.Age)
                {
                    return 0;
                }else
                {
                    return -1;
                }
               //return Age.CompareTo(s.Age); //可以直接进行比较低呀;
    
            }
    
        }
        class Program
        {
            static void Main(string[] args)
            {
               var studentList = new ArrayList();
                studentList.Add(new Student() { Age = 1, Name = "a1" });
                studentList.Add(new Student() { Age = 5, Name = "g1" });
                studentList.Add(new Student() { Age = 4, Name = "b1" });
                studentList.Add(new Student() { Age = 2, Name = "f1" });
                studentList.Sort();
                foreach (var o in studentList)
                {
                    Console.WriteLine((o as Student).Age);
                }
    
                Console.ReadLine();
    
    
            }
        }

    结果:

    如果我们不想用用年龄来比较呢;可使用IComparer来实现一个自定义的比较器

      public class SortName : IComparer
        {
    
            //接口中的定义:int Compare(object x, object y);
    
            //具体实现;
    
            public int Compare(object x,object y)
            {
                Student a = x as Student;
                Student b = y as Student;
                return a.Name.CompareTo(b.Name);
            }
        }

     使用方法:studentList.Sort(new SortName()); 

    结果:

    上面的代码我们使用了一个已经不建议使用的集合类ArrayList,当泛型出来后,所有非泛型集合类已经建议不尽量使用了。

    你可以看到上面我们再实现:

    IComparable
    IComparer
    的时候, 频发的进行拆箱和装箱操作滴呀;
    所以最好的建议是:
    代码中的ArrayList,应该换成List<T>,对应的,我们就该实现IComparable<T>和IComparer<T>。最终的代码应该像:

    总结:

    比较和排序的概念;

    2:IComparable和IComparer;

    3:IComparable和IComparer的泛型实现IComparable<T>和IComparer<T>;

    1:比较和排序的概念

        比较:两个实体类之间按>,=,<进行比较。

        排序:在集合类中,对集合类中的实体进行排序。排序基于的算法基于实体类提供的比较函数。

        基本型别都提供了默认的比较算法,如string提供了按字母进行比较,int提供了按整数大小进行比较。

    于这个 IComparable 接口,因为基本简单的值类型都有 CompareTo() 方法,而且有了 Linq 后,我只要能用 IEnumerable<T> 的集合类型,用 lambda 表达式很容易就能进行排序 Sort() 操作

     其实,对象是一个复合的数据类型;对 对象的比较,我们需要选定一个基准,要是age字段,要么是我们的name字段,或者多个字段组合比较,最终的目的是要我们自己进行自定义类的比较;

    我们这里再来看一个示例;

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication2
    {
       
        //再努力一点,也许运气会好一点;
    
       public class CarBase : IComparable
        {
            public string modleNo = "";
    
            public int CompareTo(object obj)
            {
                //定义比较的基准;
                if (obj is CarBase)
                {
                    CarBase car = obj as CarBase;
                    return this.modleNo.CompareTo(car.modleNo); //比较汽车型号 比较基准就在这里滴呀;
                }else
                {
                    throw new Exception("类型不匹配,无法进行比较");
                }
    
            }
    
    
        }
    
        public class XCAR : CarBase
        {
            public XCAR()
            {
                this.modleNo ="X";
            }
        }
    
        public class YCAR : CarBase
        {
            public YCAR()
            {
                this.modleNo = "Y";
            }
        }
    
        public class ZCAR : CarBase
        {
            public ZCAR()
            {
                this.modleNo = "Z";
            }
        }
    
        //同样,我们可以这样来实现一个东东
    
        public class CarComparer : IComparer
        {
            public int Compare(object x,object y)
            {
                //返回值 < 0表示: x小于y
                //返回值=0表示:x等于y 
                //返回值>0表示:x大于y 
                if (x is CarBase && y is CarBase)
                {
                    //这里涉及类型的转换,性能开销不划算,实际的使用过程中,建议使用泛型;
                    CarBase car1 = x as CarBase;
                    CarBase car2 = y as CarBase;
                    return car1.CompareTo(car2);
                }
                else
                throw new Exception("类型不匹配");
            }
        }
    
    
    
        class Program
        {
            static void Main(string[] args)
            {
                CarBase x = new XCAR();
                CarBase y = new YCAR();
                CarBase z = new ZCAR();
                int resutl = x.CompareTo(z);  //x<y  所以我们的结果就是:-1  两个对象之间的各种比较滴呀,效果还是满理想得啊;
                Console.WriteLine(resutl);
                object[] cars = new object[] { y,x, z };//汽车数组,用于排序,现在是无序状态 
    
                foreach(var o in cars)
                {
                    Console.WriteLine((o as CarBase).modleNo);
                }
    
                // y x z
    
                //然后进行排序;
                Array.Sort(cars,new CarComparer());
                //排序呢后的结果;
                foreach (var o in cars)
                {
                    Console.WriteLine((o as CarBase).modleNo);
                }
    
                // x y  z
                Console.ReadLine();
            }
        }
    }

     上面的方法虽然好,但是如果你想想,如果有一百个对象都要进行比较,那么,我么是不是就要写一百个对象继承自我们的BaseCar的方法呢;

    如果有更好的优化方法呢;

    参看文献:

    http://www.csframework.com/archive/2/arc-2-20110713-1710.htm

  • 相关阅读:
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 2 Messags Partterns
    WPF动态更改Image控件图片路径
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 1
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 4 Handling Errors and ETERM
    Chapter 2 Sockets and Patterns【选译,哈哈】 Part 3 Messags Partterns
    Visual Studio 2008 测试项目无法正常显示解决办法
    Ext.NET控件介绍—Form控件
    ThoughtWorks(中国)程序员读书雷达
    Ext.net 中日期格式的计算
    Sql 分割 键值对字符串 得到某值对应的名称
  • 原文地址:https://www.cnblogs.com/mc67/p/7270691.html
Copyright © 2011-2022 走看看