zoukankan      html  css  js  c++  java
  • 通用的泛型Icomparer生成类,对类进行排序,最大支持4个字段同时比较

    一,通常我们自己定义一个类,然后对类的集合进行排序,是下面这样的做法

            class People
            {
                public int ID { get; set; }
                public string Name { get; set; }
                public DateTime Birthday { get; set; }
    
                public override string ToString()
                {
                    return string.Format("{0},{1},{2}", ID, Name, Birthday);
                }
            }

     再定义一个类继承IComparer<People>接口

            /// <summary>
            /// user define
            /// </summary>
            class PeopleCompare : IComparer<People>
            {
                #region IComparer<People> 
    
                public int Compare(People x, People y)
                {
                    return Comparer<int>.Default.Compare(x.ID, y.ID);
                }
    
                #endregion
            }

     调用代码:

            public static void TestFunc()
            {
                var peoples = new People[] { 
                new People{ID = 1,Name = "a123",Birthday = new DateTime(2000,05,01)},
                new People{ID = 4,Name = "b123",Birthday = new DateTime(2000,04,01)},
                new People{ID = 2,Name = "d123",Birthday = new DateTime(2000,02,01)},
                new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,04,01)},
                };
                Array.Sort(peoples, new PeopleCompare());            
                peoples.ForEach<People>(p => System.Diagnostics.Debug.WriteLine(p));
    
            }

     结果输出如下:

    1,a123,2000/05/01 0:00:00
    2,d123,2000/02/01 0:00:00
    3,e123,2000/04/01 0:00:00
    4,b123,2000/04/01 0:00:00

    ,如果我们又定义了Cat,Monkey等等这样的类,就得每次都写一个类似于PeopleCompare的类,当然你也可以在定义People的时候继承Icomparable接口,本文不讨论。

    这样做有大量的重复工作,现在考虑定义一个泛型的方法来创建通用的继承了IComparer的类,并且考虑到类有多个字段,对多个字段的排序也考虑进去。下面的这个类定义了一个最大支持4个字段的ComparerFactory类,一般应用已经足够了。

            /// <summary>
            /// Common Comaparer Generate Class, supported 4 paramers limitted
            /// </summary>
            /// <typeparam name="T"></typeparam>
            public static class ComparerFactroy<T>
            {
                public static IComparer<T> Create<V1>(Func<T, V1> keySelector1)
                {
                    return new MyCommonComparer<V1, Object, Object, Object>(keySelector1,Comparer<V1>.Default,null,null,null, null, null, null);
                }
                public static IComparer<T> Create<V1, V2>(Func<T, V1> keySelector1, Func<T, V2> keySelector2)
                {
                    return new MyCommonComparer<V1, V2, Object, Object>(keySelector1,Comparer<V1>.Default, keySelector2,Comparer<V2>.Default,null,null, null, null);
                }
                public static IComparer<T> Create<V1, V2, V3>(Func<T, V1> keySelector1, Func<T, V2> keySelector2, Func<T, V3> keySelector3)
                {
                    return new MyCommonComparer<V1, V2, V3, Object>(keySelector1, Comparer<V1>.Default, keySelector2, Comparer<V2>.Default, keySelector3, Comparer<V3>.Default, null,null);
                }
                public static IComparer<T> Create<V1, V2, V3,V4>(Func<T, V1> keySelector1, Func<T, V2> keySelector2, Func<T, V3> keySelector3, Func<T, V4> keySelector4)
                {
                    return new MyCommonComparer<V1, V2, V3, V4>(keySelector1, Comparer<V1>.Default, keySelector2, Comparer<V2>.Default, keySelector3, Comparer<V3>.Default, keySelector4,Comparer<V4>.Default);
                }
    
                class MyCommonComparer<V1,V2,V3,V4> : IComparer<T>
                {
                    Func<T, V1> keySelector1;
                    Func<T, V2> keySelector2;
                    Func<T, V3> keySelector3;
                    Func<T, V4> keySelector4;
    
                    IComparer<V1> comparer1;
                    IComparer<V2> comparer2;
                    IComparer<V3> comparer3;
                    IComparer<V4> comparer4;
    
                    public MyCommonComparer(Func<T, V1> keySelector1, IComparer<V1> compare1,
                                            Func<T, V2> keySelector2, IComparer<V2> compare2,
                                            Func<T, V3> keySelector3, IComparer<V3> compare3,
                                            Func<T, V4> keySelector4, IComparer<V4> compare4)
                    {
                        this.keySelector1 = keySelector1;
                        this.keySelector2 = keySelector2;
                        this.keySelector3 = keySelector3;
                        this.keySelector4 = keySelector4;
                        this.comparer1 = compare1;
                        this.comparer2 = compare2;
                        this.comparer3 = compare3;
                        this.comparer4 = compare4;
                    }
                    #region IComparer<T> メンバ
    
                    public int Compare(T x, T y)
                    {
                        int retVal = 0;
                        if (keySelector1 != null)
                            retVal = comparer1.Compare(keySelector1(x), keySelector1(y));
                        if (keySelector2 != null && retVal == 0)
                            retVal = comparer2.Compare(keySelector2(x), keySelector2(y));
                        if (keySelector3 != null && retVal == 0)
                            retVal = comparer3.Compare(keySelector3(x), keySelector3(y));
                        if (keySelector4 != null && retVal == 0)
                            retVal = comparer4.Compare(keySelector4(x), keySelector4(y));
    
                        return retVal;
                    }
    
                    #endregion
                }
            }

     ComparerFactory的Create方法根据你传的类型,创建一个Comparer,Create方法有4个重载,可以对1,2,3,4个字段进行排序。

    继续用上面定义的People类测试,使用方法如下:

            public static void TestFunc()
            {
                var peoples = new People[] { 
                    new People{ID = 1,Name = "a123",Birthday = new DateTime(2000,05,01)},
                    new People{ID = 4,Name = "b123",Birthday = new DateTime(2000,04,01)},
                    new People{ID = 2,Name = "d123",Birthday = new DateTime(2000,02,01)},
                    new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,04,01)},
                    new People{ID = 3,Name = "e123",Birthday = new DateTime(2000,03,01)},
                    new People{ID = 3,Name = "c123",Birthday = new DateTime(2000,03,01)}
                    };
    
                Array.Sort(peoples, ComparerFactroy<People>.Create(p => p.ID, p => p.Name, p => p.Birthday));
    
                peoples.ForEach<People>(p => System.Diagnostics.Debug.WriteLine(p));
    
            }

     分别根据People的ID,Name,Birthday进行排序

    测试结果:

    1,a123,2000/05/01 0:00:00
    2,d123,2000/02/01 0:00:00
    3,c123,2000/03/01 0:00:00
    3,e123,2000/03/01 0:00:00
    3,e123,2000/04/01 0:00:00
    4,b123,2000/04/01 0:00:00

     
    可以继续完善的地方:

    1,现在默认是每个字段的升序排列,可以在参数中每个字段的升序降序排列。

    2,现在只支持4个字段,扩充字段代码改动较大,不知道还有没有更好的支持多字段的写法,欢迎一起讨论。

  • 相关阅读:
    暑期实践
    noi前第十九场 题解
    noi前第十八场 题解
    noi前第十七场 题解
    noi前第十六场 题解
    noi前第十五场 题解
    noi前第十四场 题解
    noi前第十三场 题解
    [NOI2017]游戏「2-SAT」
    空间宝石「最短路+线段树」
  • 原文地址:https://www.cnblogs.com/xiashengwang/p/2578783.html
Copyright © 2011-2022 走看看