У меня есть список цветов, как это:
Розовый, синий, красный, синий, серый, зеленый, фиолетовый, черный ... и т. Д.
List<String> listOfColors = Arrays.asList("Pink", "Blue", "Red", "blue", "Grey", "green", "purple", "black");
Есть некоторые промежуточные операции, такие как фильтрация цветов фруктов, теперь у меня остались отфильтрованные результаты, в которых я хочу отсортировать их по порядку:
Синий, черный, синий, серый, зеленый, розовый, фиолетовый, красный
Я пытался :
List<String> collect = listOfColors.stream().sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
Это не работает, как ожидалось.
Вывод следующий:
черный, синий, синий, зеленый, серый, розовый, фиолетовый, красный
Я хочу следующее:
Синий, черный, синий, серый, зеленый, розовый, фиолетовый, красный
java
sorting
java-8
java-stream
Вишва Ратна
источник
источник
a
раньше,u
так что результат правильный[black, Blue, blue, green, Grey, Pink, purple, Red]
@ chrylis-onstrike-Ответы:
Мое решение состоит в том, чтобы использовать сортировку в два этапа, используя
Comparator.thenComparing()
метод.Сначала сравните строки только по первому символу, игнорируя регистр. Таким образом, группы с одинаковым первым символом (независимо от того, в каком случае) пока остаются несортированными. Затем на втором шаге примените обычную сортировку по алфавиту, чтобы отсортировать эти несортированные подгруппы.
Может быть, это еще можно оптимизировать, но это дает желаемый результат:
источник
Comparator
. Но да, это предполагает только сравнение первого символа строки, о котором ОП особо не подчеркивал.Вы можете использовать RuleBasedCollator для определения ваших собственных правил.
Пример пользовательского правила:
Вывод:
Редактировать: вместо написания
customRules
от руки, вы можете использовать ниже код для его генерации.источник
String customRules
может быть автоматизмом сIntStream
:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
.mapToObj(Character::toString)
то не будет решена, я думаю, вам нужно использовать.mapToObj(c -> Character.toString((char) c))
mapToObj(Character::toString)
работает только в Java 11 или новее.mapToObj(Character::toString)
не получил решения, но мне понравилась идея, поэтому я закончил кастингом вроде.mapToObj(c -> Character.toString((char) c))
IntStream.rangeClosed('a', 'z').flatMap(c -> IntStream.of(c,Character.toUpperCase(c))) .mapToObj(c -> Character.toString((char)c)) .collect(Collectors.joining("<", "<", ""));
Вам нужен метод, который сначала выполняет сравнение без учета регистра для каждой буквы, а затем, если есть совпадение, выполняет сравнение с учетом регистра для каждой буквы:
Затем вы можете передать этот метод
Stream.sorted
.источник