Sort with two criteria, string ascending, int ascending
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
精彩评论