Invertendo um HashMap de Map para Mapear <Boolean, List >

Existe uma maneira mais elegante / integrada de reverter as chaves e os valores de um Hashmap?

Eu atualmente tenho o seguinte.

private Map<Boolean, List> reverseMap(Map permissions) { List allow = new ArrayList(); List deny = new ArrayList(); Map<Boolean, List> returnvalue = new HashMap<Boolean, List>(); for (Entry entry : permissions.entrySet()) { if(entry.getValue()) { allow.add(entry.getKey()); } else { deny.add(entry.getKey()); } } returnvalue.put(true, allow); returnvalue.put(false, deny); return returnvalue; } 

Você pode considerar o uso de uma das implementações do Multimap da Guava . Por exemplo:

 private Multimap reverseMap(Map permissions) { Multimap multimap = ArrayListMultimap.create(); for (Map.Entry entry : permissions.entrySet()) { multimap.put(entry.getValue(), entry.getKey()); } return multimap; } 

Ou mais geralmente:

 private static  Multimap reverseMap(Map source) { Multimap multimap = ArrayListMultimap.create(); for (Map.Entry entry : source.entrySet()) { multimap.put(entry.getValue(), entry.getKey()); } return multimap; } 

Eu faria algo similar (mas se você tiver que fazer esse tipo de coisa frequentemente, considere Guava), apenas substituindo a Lista por Set (parece um pouco mais consistente) e preenchendo o mapa reverso:

 private Map> reverseMap(Map permissions) { Map> returnvalue = new HashMap>(); returnvalue.put(Boolean.TRUE, new HashSet()); returnvalue.put(Boolean.FALSE, new HashSet()); for (Entry entry : permissions.entrySet()) returnvalue.get(entry.getValue()).add(entry.getKey()); return returnvalue; } 

A primeira coisa a notar é que você realmente não precisa de um mapa reverso se seus valores forem verdadeiros ou falsos. Isso fará sentido se você tiver um intervalo mais amplo de valores.

Uma maneira fácil (mas não muito elegante) de obter as inputs com um valor específico é:

 public static  Set getKeysByValue(Map map, E value) { Set keys = new HashSet(); for (Entry entry : map.entrySet()) { if (entry.getValue().equals(value)) { keys.add(entry.getKey()); } } return keys; } 

Você pode ver que isso não é tão bom se você precisar chamá-lo de vez em quando. Faz sentido ter dois mapas diferentes (direto e reverso) e adicionar inputs a ambos. Você não pode usar mapas Bidi, já que não há relação 1: 1 entre chaves e valores.

ATUALIZAÇÃO: A solução a seguir não funcionará. Ver comentários. Você também pode considerar usar um TreeMap e mantê-lo classificado com base no valor. Dessa forma, você pode ter um conjunto classificado chamando map.entrySet() qualquer momento (nega as inputs primeiro, depois permite). A desvantagem é que é apenas um conjunto.

 ValueComparator bvc = new ValueComparator(map); TreeMap sorted_map = new TreeMap(bvc); class ValueComparator implements Comparator { Map base; public ValueComparator(Map base) { this.base = base; } public int compare(Object a, Object b) { return (Boolean)base.get(a).compareTo((Boolean)base.get(b)); } } 

O BiMap Guava já fornece um método para reverter seus pares de valores-chave. Talvez você possa alterar a interface do Map em questão para BiMap ou então usar o seguinte código:

 private BiMap reverseMap(Map permissions) { BiMap bimap = HashBiMap.create(permissions); return bimap.inverse(); }