Вид с двумя критериями, строковым возрастанием, международным возрастанием

Как я могу выполнить вид на двух различных критериях?

Например, у меня есть объекты человека как:

Person со свойствами FirstName (строка), LastName, и Rank (интервал).

Данные в качестве примера как так:

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

Это должно отсортировать на FirstName в алфавитном порядке, затем на разряде, например, получающийся:

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

Дал бы тот же самый список, просто отсортированный правильно, корректный?

14
задан baron 4 March 2010 в 03:22
поделиться

4 ответа

Подход LINQ

С LINQ вы можете использовать OrderBy и ThenBy :

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

Это вернет IEnumerable . Если вам действительно нужен List , добавьте в конец .ToList () .

Если вы хотите использовать метод Sort , вам необходимо написать собственный компаратор.

РЕДАКТИРОВАТЬ: использование ToList () возвращает новый список. Если вы хотите отсортировать существующий список, вам следует использовать метод Sort , который не возвращает список, а работает с текущим списком (это метод void ).

Подход Sort / Comparer

Используйте: list.Sort (new PersonComparer ());

Вот код компаратора. Он был адаптирован из примера MSDN , поэтому я рекомендую прочитать комментарии, которые они использовали, чтобы понять, почему он так структурирован.

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);
                }
            }
        }
    }
}
21
ответ дан 1 December 2019 в 07:39
поделиться

Вы действительно были очень близки с синтаксисом лямбда сортировки на месте. Вы просто упустили тот факт, что лямбды могут быть заключены в собственную область видимости:

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

Это немного меньше усилий, чем написать свой собственный IComparer!

4
ответ дан 1 December 2019 в 07:39
поделиться

Мне нравится ответ LINQ. Если это не вариант, вы всегда можете использовать

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

чтобы строковое сравнение всегда доминировало, если оно не равно 0

4
ответ дан 1 December 2019 в 07:39
поделиться

Другие ответы кажутся более элегантными, чем этот, и заставляют меня чувствовать себя еще большим профаном, однако если вы поймете, как сортировать таким образом, вы сможете сортировать любые списки любым способом, не зная почти ничего. И нет необходимости писать целый новый класс (хотя написание класса comparer может быть полезным, если вы сортируете другие похожие списки в других частях вашего кода).

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);
    });
6
ответ дан 1 December 2019 в 07:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: