Eu tenho uma lista de cores como esta:
Rosa, azul, vermelho, azul, cinza, verde, roxo, preto ... etc
List<String> listOfColors = Arrays.asList("Pink", "Blue", "Red", "blue", "Grey", "green", "purple", "black");
Existem algumas operações intermediárias, como filtrar algumas cores de frutas, agora tenho resultados filtrados onde quero que elas sejam classificadas em ordem:
Azul, preto, azul, cinza, verde, rosa, roxo, vermelho
Eu tentei :
List<String> collect = listOfColors.stream().sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
Não funciona como esperado.
A saída é a seguinte:
preto, azul, azul, verde, cinza, rosa, roxo, vermelho
Eu quero o seguinte:
Azul, preto, azul, cinza, verde, rosa, roxo, vermelho
java
sorting
java-8
java-stream
Vishwa Ratna
fonte
fonte
a
é antes,u
então o resultado está correto[black, Blue, blue, green, Grey, Pink, purple, Red]
@ chrylis-onstrike-Respostas:
Minha solução é usar a classificação em duas etapas, usando o
Comparator.thenComparing()
métodoPrimeiro, compare as Strings apenas pelo primeiro caractere que ignora o caso. Portanto, os grupos com o mesmo primeiro caractere (não importa o caso) permanecem sem classificação até o momento. Em seguida, na segunda etapa, aplique a classificação alfabética normal para classificar os subgrupos não classificados.
Talvez ainda possa ser otimizado, mas fornece o resultado desejado:
fonte
Comparator
. Mas sim, isso pressupõe apenas a comparação do primeiro caractere da String sobre o qual o OP também não enfatizou muito.Você pode usar RuleBasedCollator para definir suas próprias regras.
Exemplo de regra personalizada :
Resultado:
Editar: Em vez de escrever à
customRules
mão, você pode usar o código abaixo para gerá-lo.fonte
String customRules
pode ser automatizada comIntStream
:IntStream.range('a', 'z' + 1) .mapToObj(Character::toString) .flatMap(ch -> Stream.of("<", ch.toUpperCase(), "<", ch)) .collect(Collectors.joining(""))
.mapToObj(Character::toString)
não será resolvido, eu acho que você precisa usar.mapToObj(c -> Character.toString((char) c))
mapToObj(Character::toString)
funciona apenas no Java 11 ou mais recente.mapToObj(Character::toString)
não estava sendo resolvido, mas gostei da idéia, então acabei fazendo casting como.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("<", "<", ""));
Você precisa de um método que faça primeiro uma comparação sem distinção entre maiúsculas e minúsculas em cada letra e, se houver uma correspondência, faça uma comparação com distinção entre maiúsculas e minúsculas em cada letra:
Você pode então passar esse método para
Stream.sorted
.fonte