Пользовательский вид List<string>

У меня есть List<string>, где записи представляют собой местоположения, такие как «010101», «010102», «010201», ..., со следующим значением:

  • Первые два символа: пол
  • Следующие два символа: переулок
  • Последние два символа: вход в полосу

Обычная сортировка показывает список, подобный следующему:

010101
010102
010103
010201
010202
020101
020102
020201
020202
020203
020204
...

Я хотел бы пользовательскую сортировку, где:

  • на этаже "01" сортировка производится обычным образом:

      010101
      010102
      010103
      010201
      010202
    
  • на этаже "02" сортировка выполняется в обратном порядке для полосы, но не для входа в полосу, поэтому что-то вроде:

      ...
      020201
      020202
      020203
      020204
      020101
      020102
    

Здесь на сайте я нашел IEnumerable в качестве решения, но это работает только для List<T>, где T — новый класс. Здесь это не имеет значения, так как я имею дело с «простыми» строками. Я также нашел Enumerable в качестве решения, но это тоже не работает, потому что список возможных строк слишком велик (не поддается перечислению), и я бы предпочел гибкое решение.

У кого-нибудь есть идея?

заранее спасибо

Похоже, вам нужно реализовать IComparer<string> (или делегат Comparison<string>) и передать это вызову List<T>.Sort. Трудно понять, что вы подразумеваете под «IEnumerable как решение» — IEnumerable — это просто интерфейс. (Точно так же «Я также нашел Enumerable в качестве решения» — это просто класс, содержащий методы расширения.) По сути, я подозреваю, что вам лучше всего определить класс для представления информации в строках и анализа перед сортировкой, но это немного другое дело - более насущная проблема в том, что ваш вопрос очень неясен.

Jon Skeet 17.04.2023 08:34

Я имею в виду, что я искал на сайте решение. Решения, которые я нашел, были неприменимы либо потому, что я не могу создать новый класс, либо потому, что у меня слишком много строк, и я не могу использовать подход Enumerable.

Dominique 17.04.2023 08:38

Ваше описание решений настолько расплывчато, что мы действительно не можем сказать, являются ли они разумной отправной точкой или нет. Мы не знаем, что вы подразумеваете под «перечислимым подходом» или каковы ваши требования. (Сколько строк и что пойдет не так, когда вы попробуете то, что вы называете «перечислимым подходом»?)

Jon Skeet 17.04.2023 08:43

Я нашел сообщение человека, пытающегося отсортировать список "C", "D", "G", "T" как "D", "G", "T", "C". Для этого был создан Enumerable на основе этих четырех символов. Этот подход (который я называю подходом Enumerable) здесь невозможен, так как количество возможных строк слишком велико.

Dominique 17.04.2023 08:45

Нет, экземпляр Enumerable точно не создавался, потому что Enumerable — статический класс. Знаете ли вы, что List<T> реализует IEnumerable<string>? До сих пор неясно, пытались ли вы предоставить собственное сравнение с List<T>.Sort, если честно...

Jon Skeet 17.04.2023 08:56

Там больше двух этажей?

Enigmativity 17.04.2023 12:44

@Enigmativity: Нет, их всего два, поэтому достаточно ответа Стефана Бауэра.

Dominique 17.04.2023 13:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
77
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Есть несколько способов добиться желаемого поведения, например. используя Сравнение<string>:

var input = new List<string>() { "010101", "010102", "010103", "010201", "010202", "020101", "020102", "020201", "020202", "020203", "020204" };

Comparison<string> comparison = (s1, s2) =>
{
    if (s1 == null) throw new ArgumentNullException(nameof(s1));
    if (s2 == null) throw new ArgumentNullException(nameof(s2));
    if (s1.Length != 6 || s2.Length != 6) throw new ArgumentOutOfRangeException();

    // Compare floor (first 2 digits)
    var floor1 = s1.Substring(0, 2);
    var floor2 = s2.Substring(0, 2);
    var result = floor1.CompareTo(floor2);
    if (result != 0) return result;

    // Compare lane (middle 2 digits)
    var lane1 = s1.Substring(2, 2);
    var lane2 = s2.Substring(2, 2);
    // Special case: in floor 02, reverse order of lanes
    result = floor1 == "02"
       ? lane2.CompareTo(lane1) 
       : lane1.CompareTo(lane2);
    if (result != 0) return result;

    // Compare entry (last 2 digits)
    return s1.Substring(4, 2).CompareTo(s2.Substring(4, 2));
};

// Sort the list using the comparison defined before
input.Sort(comparison);

Этот подход отлично подходит для сортировки строк, но представленная проблема кажется лучше решенной с помощью объекта для отслеживания пола, полосы и входа в полосу. Также было бы проще манипулировать этими полями, и результат переопределял бы .ToString для представления того, что они хотят.

TheEvilMetal 17.04.2023 09:00

Не рекомендуется возвращать -result, чтобы инвертировать результат — если result равно int.MinValue, то -result также будет int.MinValue. Вероятно, самое простое надежное изменение — это return -Math.Sign(result). Альтернативой может быть использование result = floor1 == "02"? lane2.CompareTo(lane1) : lane1.CompareTo(lane2);

Jon Skeet 17.04.2023 12:08

Если ваш ввод хорошо подобран (т.е. все цифры и все 6 символов), то это простой способ сделать это:

var input = new List<string>()
{
    "010101", "010102", "010103", "010201", "010202",
    "020101", "020102", "020201", "020202", "020203", "020204"
};

var output =
    input
        .Select(x => new
        {
            location = x,
            floor = int.Parse(x.Substring(0, 2)),
            lane = int.Parse(x.Substring(2, 2)),
            entry = int.Parse(x.Substring(4, 2))
        })
        .OrderBy(x =>
            x.floor * 10000
            + (x.floor % 2 == 0 ? 99 - x.lane : x.lane) * 100
            + x.entry)
        .Select(x => x.location)
        .ToList();

Это производит:

010101 
010102 
010103 
010201 
010202 
020201 
020202 
020203 
020204 
020101 
020102 

Ваш ответ - отличное расширение, основанное на нечетных/четных номерах этажей. Спасибо.

Dominique 17.04.2023 13:03

Другие вопросы по теме