开发者

Sort with two criteria, string ascending, int ascending

开发者 https://www.devze.com 2022-12-22 07:48 出处:网络
How can I perform a sort on two different criteria? For example, I have person objects like: Person with properties FirstName (string), LastName, and Rank (int).

How can I perform a sort on two different criteria?

For example, I have person objects like:

Person with properties FirstName (string), LastName, and Rank (int).

Example data like s开发者_开发百科o:

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

It should sort on FirstName alphabetically, then on rank, e.g. resulting:

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

So far, I have tried the following, but it isn't working properly:

peopleList is List<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)));

Thanks

edit: to avoid changing my code too much, I really want to keep list, if I change the above lines to:

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

Would give the exact same list just sorted properly, correct?


LINQ Approach

With LINQ you can use OrderBy and ThenBy:

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

This will return an IEnumerable<T>. If you really need a List<T> add a .ToList() at the end.

If you want to use the Sort method then you'll need to write a custom comparer.

EDIT: using ToList() returns a new list. If you want to sort your existing list then you should use the Sort method which does not return a list but rather operates on the current list (it is a void method).

Sort / Comparer Approach

Use: list.Sort(new PersonComparer());

Here's the comparer code. It was adapted from the MSDN example so I recommend reading the comments they used to understand why it is structured this way.

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);
                }
            }
        }
    }
}


The other answers seem to be more elegant than this and they make me feel like more of a noob, however if you understand how to sort like this, you can sort any kind of list in any way without knowing much of anything. And there's no need to write a whole new class (though writing a comparer class can be useful if you sort other similar lists in other parts of your code).

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);
    });


You were actually really close with the in-place sorting lambda syntax. You're just missing the fact that lambdas can be enclosed in their own scope:

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

It's a little less effort than writing your own IComparer<Person>!


I like the LINQ answer. If that's not an option, you could always use

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

so that the string compare always dominates unless it equals 0

0

精彩评论

暂无评论...
验证码 换一张
取 消