• 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

  • 相关阅读:
    设计模式——原型链模式之在原型上设置属性
    设计模式——原型链模式
    设计模式——构造函数模式
    设计模式——工厂模式
    设计模式——单例模式
    为什么做java的web开发我们会使用struts2,springMVC和spring这样的框架?(转载)
    Unity3d中设置UISprite图片灰显方法
    游戏后端主程工作内容及游戏项目中的注意事项及游戏项目中注意事项<转载>
    xcode使用
    ios学习笔记2
  • 原文地址:https://www.cnblogs.com/mc67/p/7270691.html
Copyright © 2020-2023  润新知