Сортировка по двум критериям: по возрастанию, по возрастанию
Как я могу выполнить сортировку по двум различным критериям?
Например, у меня есть персональные объекты вроде:
Person
со свойствами FirstName
(строка), LastName
и Rank
(int).
Пример таких данных:
Xavier Smith 1
Alexander Smith 2
Alexander Smith 1
Bob Hawke 2
Он должен сортировать по первому имени в алфавитном порядке, затем по рангу, например. в результате чего:
Alexander Smith 1
Alexander Smith 2
Bob Hawke 2
Xavier Smith 1
До сих пор я пробовал следующее, но он не работает должным образом:
peopleList
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)));
Спасибо
изменить:, чтобы избежать слишком большого изменения моего кода, я действительно хочу сохранить список, если я изменил приведенные выше строки на:
peopleList.OrderBy(person => person.FirstName).ThenBy(person => person.Rank).ToList();
Дал бы тот же список, который был правильно отсортирован, правильно?
Ответы
Ответ 1
Подход LINQ
С LINQ вы можете использовать OrderBy и ThenBy:
var result = peopleList.OrderBy(p => p.FirstName).ThenBy(p => p.Rank);
Это вернет IEnumerable<T>
. Если вам действительно нужно List<T>
добавить .ToList()
в конец.
Если вы хотите использовать метод Sort
, тогда вам нужно будет написать собственный сопоставитель.
EDIT: использование ToList()
возвращает новый список. Если вы хотите отсортировать существующий список, вы должны использовать метод Sort
, который не возвращает список, а скорее работает с текущим списком (это метод void
).
Метод сортировки/сравнения
Использование: list.Sort(new PersonComparer());
Вот код сравнения. Он был адаптирован из примера
Ответ 2
Другие ответы кажутся более элегантными, чем это, и они заставляют меня чувствовать себя больше noob, однако, если вы поймете, как это сделать, вы можете сортировать любой список в любом случае, не зная ничего. И нет необходимости писать целый новый класс (хотя запись класса сравнения может быть полезна, если вы сортируете другие похожие списки в других частях вашего кода).
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
На самом деле вы были действительно близки к синтаксису лямбда-сортировки на месте. Вам просто не хватает того, что лямбды могут быть заключены в их пределах:
peopleList.Sort(new Comparison<Person>((x,y) =>
{
int result = x.FirstName.CompareTo(y.FirstName);
return (result != 0) ? result : x.Rank.CompareTo(y.Rank);
}));
Это немного меньше усилий, чем написание собственного IComparer<Person>
!