Mam listę takich kolorów:
Różowy, niebieski, czerwony, niebieski, szary, zielony, fioletowy, czarny ... itp
List<String> listOfColors = Arrays.asList("Pink", "Blue", "Red", "blue", "Grey", "green", "purple", "black");
Istnieje kilka operacji pośrednich, takich jak filtrowanie niektórych kolorów owoców, teraz mam filtrowane wyniki tam, gdzie chcę je posortować:
Niebieski, czarny, niebieski, szary, zielony, różowy, fioletowy, czerwony
Próbowałem :
List<String> collect = listOfColors.stream().sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
Nie działa zgodnie z oczekiwaniami.
Dane wyjściowe są następujące:
czarny, niebieski, niebieski, zielony, szary, różowy, fioletowy, czerwony
Chcę:
Niebieski, czarny, niebieski, szary, zielony, różowy, fioletowy, czerwony
java
sorting
java-8
java-stream
Vishwa Ratna
źródło
źródło
a
jest wcześniej,u
więc wynik jest poprawny[black, Blue, blue, green, Grey, Pink, purple, Red]
@ chrylis-onstrike-Odpowiedzi:
Moim rozwiązaniem jest użycie sortowania w dwóch krokach za pomocą
Comparator.thenComparing()
metody.Najpierw porównaj ciągi tylko przez pierwszy znak, ignorując wielkość liter. Grupy z tą samą pierwszą postacią (bez względu na przypadek) pozostają do tej pory nieposortowane. Następnie w drugim kroku zastosuj normalne sortowanie alfabetyczne, aby posortować te nieposortowane podgrupy.
Być może można go jeszcze zoptymalizować, ale daje pożądany rezultat:
źródło
Comparator
. Ale tak, zakłada to jedynie porównanie pierwszego znaku Ciągu, o którym OP również nie podkreślił zbyt wiele.Możesz użyć RuleBasedCollator do zdefiniowania własnych reguł.
Przykład niestandardowej reguły:
Wynik:
Edycja: Zamiast pisać
customRules
ręcznie, możesz użyć poniższego kodu, aby go wygenerować.źródło
String customRules
może być automatyzmem zIntStream
:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
.mapToObj(Character::toString)
nie zostanie rozwiązany, myślę, że musisz użyć.mapToObj(c -> Character.toString((char) c))
mapToObj(Character::toString)
działa tylko w Javie 11 lub nowszej.mapToObj(Character::toString)
nie byłem rozwiązany, ale spodobał mi się ten pomysł, więc skończyłem na castingu jak.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("<", "<", ""));
Potrzebujesz metody, która najpierw rozróżnia wielkość liter dla każdej litery, a następnie, jeśli istnieje dopasowanie, wykonaj porównanie wielkości liter dla każdej litery:
Następnie możesz przekazać tę metodę do
Stream.sorted
.źródło