学习记录 C# IComparer接口 多字段排序,递进排序

背景:

 

 工作中遇到这种排序场景,就不能单一使用System.Linq.Enumerable 中的扩展方法  OrderBy,OrderByDescending 排序方式了。

实现该需求有不同的方式 记录一下:

测试代码:

    public class Student
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public int Height { get; set; }

        public int Weight { get; set; }


        public int Score { get; set; }

        public override string ToString()
        {
            return nameof(Name) + ":" + Name + "," + nameof(Age) + ":" + Age + "," + nameof(Height) + ":" + Height + "," + nameof(Weight) + ":" + Weight + "," + nameof(Score) + ":" + Score;
        }
    }
            List<Student> list = new List<Student> {
            new Student{ Name  = "Bob",Age = 29,Height = 180,Weight = 60,Score = 100},
            new Student{ Name  = "Foo",Age = 25,Height = 176,Weight = 67,Score = 89},
            new Student{ Name  = "Jam",Age = 25,Height = 176,Weight = 67,Score = 99},
            new Student{ Name  = "Alice",Age = 31,Height = 169,Weight = 66,Score = 87},
            new Student{ Name  = "Nura",Age = 31,Height = 160,Weight = 70,Score = 78}
            };

 

 

1:使用内置的排序方式,硬编码不同的字段

命名空间:System.Linq 下 有 ThenByDescending ,Enumerable.ThenBy 扩展方法 用于在 调用 OrderBy  OrderByDescending之后调用,按升序,降序 对序列中的元素执行后续排序。

 
public static System.Linq.IOrderedEnumerable<TSource> ThenBy<TSource,TKey> (this System.Linq.IOrderedEnumerable<TSource> source, Func<TSource,TKey> keySelector);
    Console.WriteLine("排序前:");
            foreach (var item in list) Console.WriteLine(item.ToString());

            //测试升序排列:Age 排序 当Age相同 Height排序 当Height相同 Weight排序 当Weight相同 Score排序……
            Console.WriteLine();
            Console.WriteLine("System.Linq.Enumerable 中的扩展 内置排序:");
            list = list.OrderByDescending(c => c.Age).ThenBy(c => c.Height).ThenBy(c => c.Weight).ThenBy(c => c.Score).ToList();
            Console.WriteLine("排序后:");
            foreach (var item in list) Console.WriteLine(item.ToString());

输出如下:

 

 

 

 

2:通过实现IComparer<Student>接口 自定义排序

示例代码:

   public class MyCompare : IComparer<Student>
    {

        /// <summary>
        /// 动态排序字段
        /// </summary>
        public readonly string[] PropNames;
        public MyCompare(string[] propNames)
        {
            //PropNames = string[]{ "Age", "Height", "Weight", "Score" };
            PropNames = propNames;
        }

        public int Compare(Student x, Student y)
        {
            int i = PropNames.Length;
            return InnerCompare(x, y, i);
        }


        private int InnerCompare(Student x, Student y, int i)
        {

            for (int j = 0; j < i; j++)
            {
                var propName = PropNames[j];
                var prop = typeof(Student).GetProperty(propName);
                var xValue = prop.GetValue(x);
                var yValue = prop.GetValue(y);

                //当具有不同的数据类型
                //if (xValue.GetType() == typeof(int))

                int xCurrentPropValue = Convert.ToInt32(xValue);
                int yCurrentPropValue = Convert.ToInt32(yValue);
                if (xCurrentPropValue != yCurrentPropValue)
                {
                    return xCurrentPropValue.CompareTo(yCurrentPropValue);
                }
                else
                {
                    return InnerCompare(x, y, j + 1);
                }
            }
            return 0;
        }


    }

 

 输出如下:

 

 

 

说明:

C#中有 IComparable、IComparer接口

前者 定义通用比较方法 排序实现的最底层逻辑,后者定义排序方式 借助于IComparable接口

如示例代码中的  return xCurrentPropValue.CompareTo(yCurrentPropValue); CompareTo方法还是依赖于默认实现了的IComparable接口中的 CompareTo方法。

 
posted @ 2022-04-27 10:54  rhyswang  阅读(330)  评论(0编辑  收藏  举报