【问题标题】:Sort with two criteria, string ascending, int ascending使用两个条件排序,字符串升序,int升序
【发布时间】:2011-01-23 12:20:11
【问题描述】:

如何根据两个不同的条件进行排序?

例如,我有如下人员对象:

Person 具有属性 FirstName(字符串)、LastNameRank(整数)。

示例数据如下:

Xavier    Smith 1
Alexander Smith 2
Alexander Smith 1
Bob       Hawke 2

它应该按名字的字母顺序排序,然后按排名,例如结果:

Alexander Smith 1
Alexander Smith 2
Bob       Hawke 2
Xavier    Smith 1

到目前为止,我已经尝试了以下方法,但无法正常工作:

peopleListList<Person>

peopleList.Sort(new Comparison<Person>((x,y) => x.Rank.CompareTo(y.Rank)));
peopleList.Sort(new Comparison<Person>((x, y) => string.Compare(x.Name, y.Name)));

谢谢

编辑:为了避免过多地更改我的代码,我真的想保留列表,如果我将上面的行更改为:

peopleList.OrderBy(person => person.FirstName).ThenBy(person => person.Rank).ToList();

会给出刚刚正确排序的完全相同的列表,对吗?

【问题讨论】:

    标签: c# list sorting


    【解决方案1】:

    LINQ 方法

    使用 LINQ,您可以使用 OrderByThenBy

    var result = peopleList.OrderBy(p => p.FirstName).ThenBy(p => p.Rank);
    

    这将返回一个IEnumerable&lt;T&gt;。如果您确实需要 List&lt;T&gt;,请在末尾添加 .ToList()

    如果您想使用Sort 方法,那么您需要编写一个自定义比较器。

    编辑:使用ToList() 返回一个新列表。如果要对现有列表进行排序,则应使用 Sort 方法,该方法不返回列表,而是对当前列表进行操作(它是 void 方法)。

    排序/比较方法

    使用:list.Sort(new PersonComparer());

    这是比较器代码。它改编自MSDN example,因此我建议您阅读他们使用的 cmets,以了解为什么采用这种结构。

    public class PersonComparer : IComparer<Person>
    {
        public int Compare(Person x, Person y)
        {
            if (x == null)
            {
                if (y == null)
                {
                    return 0;
                }
                else
                {
                    return -1;
                }
            }
            else
            {
                if (y == null)
                {
                    return 1;
                }
                else
                {
                    int retval = x.FirstName.CompareTo(y.FirstName);
    
                    if (retval != 0)
                    {
                        return retval;
                    }
                    else
                    {
                        return x.Rank.CompareTo(y.Rank);
                    }
                }
            }
        }
    }
    

    【讨论】:

    • 我真的必须阅读更多关于 LINQ 的内容,它似乎让我的生活变得轻松多了!
    • @baron 看到我的编辑,我在你最近的编辑中评论了你的问题。
    • @baron 我添加了一个可与Sort() 一起使用的比较器。
    • 感谢您的彻底回答艾哈迈德
    • @baron 不客气 :) 这里还有其他一些不错的答案。 CompareTo 的想法是查看项目是否相等、更大或更小,然后根据整数返回值进行排序。正如其他人所展示的那样,使用返回语句或 lambda 中使用的一些三元运算符当然可以减小比较器的大小。如果您打算在许多地方使用这种类型的比较,则有一个类会有所帮助,否则可以在没有新类的情况下进行很少的比较。
    【解决方案2】:

    其他答案似乎比这更优雅,它们让我感觉更像是一个菜鸟,但是如果你了解如何像这样排序,你可以以任何方式对任何类型的列表进行排序,而无需了解太多。并且没有必要编写一个全新的类(尽管如果您在代码的其他部分对其他类似列表进行排序,编写一个比较器类会很有用)。

    peopleList.Sort((x, y) =>
        {
            int compare = x.FirstName.CompareTo(y.FirstName);
            if (compare != 0)
                return compare;
    
            compare = x.Rank.CompareTo(y.Rank);
            if (compare != 0)
                return compare;
    
            return x.LastName.CompareTo(y.LastName);
        });
    

    【讨论】:

      【解决方案3】:

      我喜欢 LINQ 的答案。如果这不是一个选项,您可以随时使用

      (x,y) => 2*string.Compare(x.Name,y.Name) + x.Rank.CompareTo(y.Rank)
      

      这样字符串比较总是占主导地位,除非它等于 0

      【讨论】:

        【解决方案4】:

        您实际上非常接近就地排序 lambda 语法。您只是错过了 lambda 可以包含在自己的范围内的事实:

        peopleList.Sort(new Comparison<Person>((x,y) =>
        {
            int result = x.FirstName.CompareTo(y.FirstName);
            return (result != 0) ? result : x.Rank.CompareTo(y.Rank);
        }));
        

        这比编写自己的IComparer&lt;Person&gt; 更省力!

        【讨论】:

        • @Aaronaught 非常好,但您需要翻转比较。首先比较 FirstName,然后在三元比较排名的第二部分。
        猜你喜欢
        • 2019-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-08
        • 1970-01-01
        • 2018-03-24
        • 2012-04-03
        相关资源
        最近更新 更多