Quero escrever um comparador que permita classificar um TreeMap por valor, em vez da ordem natural padrão.
Eu tentei algo assim, mas não consigo descobrir o que deu errado:
import java.util.*;
class treeMap {
public static void main(String[] args) {
System.out.println("the main");
byValue cmp = new byValue();
Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
for (Map.Entry<String,Integer> pair: map.entrySet()) {
System.out.println(pair.getKey()+":"+pair.getValue());
}
}
}
class byValue implements Comparator<Map.Entry<String,Integer>> {
public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
if (e1.getValue() < e2.getValue()){
return 1;
} else if (e1.getValue() == e2.getValue()) {
return 0;
} else {
return -1;
}
}
}
Acho que o que estou perguntando é: Posso passar um Map.Entry
passe para o comparador?
Respostas:
Você não pode
TreeMap
classificar os valores, pois isso desafia aSortedMap
especificação:No entanto, usando uma coleção externa, você sempre pode classificar da maneira
Map.entrySet()
que desejar, por chaves, valores ou até mesmo uma combinação (!!) das duas.Aqui está um método genérico que retorna um
SortedSet
deMap.Entry
, dados aMap
cujos valores sãoComparable
:Agora você pode fazer o seguinte:
Observe que coisas descoladas acontecerão se você tentar modificar o
SortedSet
próprio, ou oMap.Entry
interior, porque essa não é mais uma "visualização" do mapa originalentrySet()
.De um modo geral, a necessidade de classificar as entradas de um mapa por seus valores é atípica.
Nota
==
paraInteger
Seu comparador original compara
Integer
usando==
. Isso quase sempre está errado, já que==
comInteger
operandos é uma igualdade de referência, não uma igualdade de valor.Perguntas relacionadas
new Integer(i) == i
em Java? (SIM!!!)fonte
resposta de poligenelubricants é quase perfeita. Ele tem um bug importante. Ele não manipula entradas de mapa onde os valores são os mesmos.
Este código: ...
Saída:
Observe como nossa vaca desapareceu ao compartilhar o valor "1" com o nosso macaco: O!
Esta modificação do código resolve esse problema:
fonte
Set
implementação contém um elemento mais de uma vez. Você acabou de violar essa restrição. A partir daSortedSet
API: Note que a ordem mantida por um conjunto classificado deve ser consistente com iguais ... . A solução seria mudar para umaList
implementação.Set
s aqui. Desde queComparator
viola oSet
contratoSet.remove
,Set.contains
etc não funciona ! Veja este exemplo em ideone .int res= e1.getValue().compareTo(e2.getValue());
paraint res= e2.getValue().compareTo(e1.getValue());
, você tem valores ordem decrescente em vez de ascendente.res != 0 ? res : e1.getKey().compareTo(e2.getKey())
a preservar a ordem das chaves com valores iguais.No Java 8:
fonte
A
TreeMap
é sempre classificado pelas teclas, qualquer outra coisa é impossível. AComparator
apenas permite controlar como as chaves são classificadas.Se você deseja que os valores classificados, você deve extraí-los
List
e ordená- los .fonte
Isso não pode ser feito usando a
Comparator
, pois ele sempre compara a chave do mapa.TreeMap
só pode classificar pela chave.fonte
SortedMap
que especifica a classificação por teclas) beginnersbook.com/2014/07/...Comparator
usa um mapa existente para obter os valores por ordem. Em outras palavras, ele não pode classificar valores arbitrários colocadosTreeMap
posteriormente, apenas valores que já estão no mapa original.A resposta de Olof é boa, mas precisa de mais uma coisa antes de ser perfeita. Nos comentários abaixo de sua resposta, dacwe (corretamente) ressalta que sua implementação viola o contrato Compare / Igual a Conjuntos. Se você tentar chamar a opção contém ou remover uma entrada que esteja claramente no conjunto, o conjunto não o reconhecerá devido ao código que permite que entradas com valores iguais sejam colocadas no conjunto. Portanto, para corrigir isso, precisamos testar a igualdade entre as chaves:
"Observe que a ordem mantida por um conjunto classificado (se um comparador explícito é ou não fornecido) deve ser consistente com iguais se o conjunto classificado deve implementar corretamente a interface Set ... a interface Set é definida em termos da operação igual , mas um conjunto classificado executa todas as comparações de elementos usando seu método compareTo (ou compare), portanto, dois elementos que são considerados iguais por esse método são, do ponto de vista do conjunto classificado, iguais . " ( http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html )
Como originalmente ignoramos a igualdade para forçar o conjunto a adicionar entradas com valores iguais, agora precisamos testar a igualdade nas chaves para que o conjunto realmente retorne a entrada que você está procurando. Isso é meio confuso e definitivamente não é como os aparelhos deveriam ser usados - mas funciona.
fonte
Eu sei que este post pede especificamente a classificação de um TreeMap por valores, mas para aqueles que realmente não se importam com a implementação, mas desejam uma solução que mantenha a coleção classificada à medida que os elementos forem adicionados, eu gostaria de receber feedback sobre esse TreeSet baseado em solução. Por um lado, os elementos não são facilmente recuperados por chave, mas para o caso de uso que eu tinha em mãos (localizando as n chaves com os valores mais baixos), isso não era um requisito.
fonte
Muitas pessoas ouvem conselhos para usar a Lista e eu prefiro usá-la também
Aqui estão dois métodos para ordenar as entradas do mapa de acordo com seus valores.
fonte