Сортировка по убыванию с подчеркиванием в строке

Я пытаюсь выполнить сортировку по убыванию столбца, содержащего в строке подчеркивание. Это мой метод сортировки по убыванию.

protected void validateDescendingOrder(Integer column) {
    // create a column list
    List<String> columnList = getColumnList(column);

    // create a new list and sort
    List<String> sortedcolumnList = new ArrayList<String>();
    sortedcolumnList.addAll(columnList);
    Collections.sort(sortedcolumnList, new Comparator<String>() {
    public int compare(String o1, String o2) {
        if (o1.contains("_") && o2.contains("_")) {
            return compare(o1.substring(1), o2.substring(1));
        }

        if (o1.contains("_")) {
            return 1;
        }
        if (o2.contains("_")) {
            return -1;
        }

        return o1.compareTo(o2);
    }
});

// sort the list using the custom comparator
Collections.sort(sortedcolumnList, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));
//sortedcolumnList.sort(customComparator);
System.out.println(sortedcolumnList);
System.out.println(columnList);
    
// compare the original list order with the sorted list to make sure they match
assertEquals(sortedcolumnList, columnList);

Я ожидаю, что мой род вернется Test_jenn, Test_Community, TestRelease, TestCom1, test1, но вместо этого возвращается TestRelease, TestCom1, Test_jenn, Test_Community, test1

Каков именно ваш предполагаемый порядок, когда обе строки содержат «_»? У вас это получается, вы сравниваете строки, начиная со второй буквы. Это выглядит подозрительно. Вы уверены, что это то, что вы хотите сделать?

k314159 11.07.2024 19:54

Кроме того, я не вижу никаких попыток сделать это спускающимся. У вас это сортировка по возрастанию, поскольку это значение по умолчанию. И вы хотите, чтобы он был нечувствителен к регистру? Тогда вам придется это указать.

k314159 11.07.2024 19:57

пожалуйста, опубликуйте минимальный воспроизводимый пример - опубликованный код ничего не возвращает - а также опубликуйте правильные примеры - я не верю, что sortedcolumnList имеет test1 в конце

user85421 11.07.2024 19:58

как упоминалось в k314159, if (o1.contains"_") return 1; означает, что все, что содержит подчеркивание, больше, чем что-то без подчеркивания (и больше сортируется до конца, а не до начала, как вы ожидаете. || o1.compareTo(o2) также не будет сортироваться в порядке убывания. || запуск опубликованного кода с заданными строками заканчивается на sortedcolumnList = [TestCom1, TestRelease, test1, Test_Community, Test_jenn], а не на то, что было опубликовано

user85421 11.07.2024 20:18

Вам будет полезно запустить этот код с помощью отладчика. Отладчик позволит вам установить точку останова и запускать код по одной строке, отслеживая значения переменных. Когда код делает что-то, противоречащее вашему прогнозу? Каковы были значения переменных в то время?

Old Dog Programmer 11.07.2024 20:48

Как вы хотите, чтобы код сравнивал пару строковых объектов, если каждый из них имеет _, но различается до _? Например, как следует сравнивать Test_jenn и Register_jenn? или Test_jenn и Quiz_Community?

Old Dog Programmer 11.07.2024 20:53

@ k314159 k314159, извини, мне не удалось опубликовать часть кода, посвященную обратной сортировке. Я отредактировал сообщение, чтобы оно содержало это.

kc29 11.07.2024 23:07

@ user85421, мне не удалось опубликовать обратную сортировку, но я изменил выше, указав, где я выполняю сортировку. Примеры, которые я привел, - это мой реальный код, который вызывает у меня проблемы и неправильно сортирует.

kc29 11.07.2024 23:13

последний sort по сути переопределяет предыдущий, то есть просто сортирует записи (в порядке, обратном CASE_INSENSITIVE_ORDER) || возможно, вы хотите Collections.sort(sortedcolumnList, Collections.reverseOrder(new Comparator<String>() { ... с предыдущим компаратором... или просто добавьте .reversed() после компаратора (Collections.sort(sortedcolumnList, new Comparator<String>() { ... }.reversed());)

user85421 11.07.2024 23:30

(другими словами, reversedOrder() не меняет фактический порядок, он меняет компаратор, заданный в качестве параметра, а затем sort() начинает новую сортировку, (почти) игнорируя фактический порядок элементов)

user85421 11.07.2024 23:38

(( другая возможность перевернуть компаратор — поменять местами аргументы (o1 <-> o2)) ​​— также рассмотрите String.compareToIgnoreCase()

user85421 11.07.2024 23:57
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
11
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Проблема

Collections.sort() вызывается дважды, и поскольку вызов Collections.sort() пересортирует список, предыдущая сортировка (почти)¹ игнорируется.

Опубликованный код в основном:

Collections.sort(list, comparator1);
Collections.sort(list, comparator2);

таким образом, результирующий порядок соответствует тому, который задан компаратором2 - reverseOrder(CASE_INSENSITIVE_ORDER).
Сортировка compartor1 — анонимного класса, использующего символы подчеркивания — игнорируется!

То есть сделать что-то вроде:

Collections.sort(list, Collections.reverseOrder(comparator3));

не меняет предыдущий порядок списка; он сортирует, используя заданный comparator3 в обратном порядке. В опубликованном коде компаратор переворачивается — String.CASE_INSENSITIVE_ORDER, поэтому список сортируется в порядке убывания строк без учета регистра.

Решения

Удалить вторую сортировку

Collections.sort(sortedcolumnList, Collections.reverseOrder(String.CASE_INSENSITIVE_ORDER));`

Альтернативы для отмены анонимного компаратора:

  1. используйте Collections#reverseOrder
Collections.reverseOrder( new Comparator<String>() {
    public int compare(String o1, String o2) {
        if (o1.contains("_") && o2.contains("_")) {
            return compare(o21.substring(1), o2.substring(1));
        }

        if (o2.contains("_")) {
            return 1;
        }
        if (o1.contains("_")) {
            return -1;
        }

        return o2.compareTo(o1);
    }
} )
  1. просто поменяйте местами аргументы compare
    Внимание: не меняйте местами аргументы рекурсивного вызова!
new Comparator<String>() {
    public int compare(String o1, String o2) {
        if (o1.contains("_") && o2.contains("_")) {
            return compare(o21.substring(1), o2.substring(1));
        }

        if (o2.contains("_")) {
            return 1;
        }
        if (o1.contains("_")) {
            return -1;
        }

        return o2.compareTo(o1);
    }
}
  1. или инвертируйте результат
    Внимание: не инвертируйте результат рекурсивного вызова!
new Comparator<String>() {
    public int compare(String o1, String o2) {
        if (o1.contains("_") && o2.contains("_")) {
            return compare(o1.substring(1), o2.substring(1));
        }

        if (o1.contains("_")) {
            return -1;
        }
        if (o2.contains("_")) {
            return 1;
        }

        return - o1.compareTo(o2);
    }
}

Примечания

  1. Нечувствителен к регистру
    Чтобы получить регистронезависимый порядок в приведенных выше кодах, используйте compareToIgnoreCase() вместо ignoreTo().

  2. Рекурсивный вызов
    Я не уверен, какова цель рекурсивного вызова compare. Мне кажется, это дорогой и подверженный ошибкам способ игнорировать все, что находится до подчеркивания в обеих строках. Метод compare в конечном итоге может быть вызван для сравнения каждого элемента друг с другом, то есть его можно вызывать очень часто, нерекурсивное решение было бы более подходящим. Предложение: вместо contains используйте indexOf() для поиска по подчеркиваниям и substring() для игнорирования всего до этого индекса.

as I wrote, not sure what the exact requirement are.


1 - Collections#sort «гарантированно стабильный: в результате сортировки порядок одинаковых элементов не будет переупорядочен». (javadoc)

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