Mapa que podría repetirse en el orden de los valores

Necesito un mapa que pueda repetirse en el orden decreciente de sus valores . ¿Alguna de las bibliotecas estándar como Apache Commons o Guava proporciona este tipo de mapa?

Haría esto con Guava de la siguiente manera:

 Ordering> entryOrdering = Ordering.from(valueComparator) .onResultOf(new Function, Value>() { public Value apply(Entry entry) { return entry.getValue(); } }).reverse(); // Desired entries in desired order. Put them in an ImmutableMap in this order. ImmutableMap.Builder builder = ImmutableMap.builder(); for (Entry entry : entryOrdering.sortedCopy(map.entrySet())) { builder.put(entry.getKey(), entry.getValue()); } return builder.build(); // ImmutableMap iterates over the entries in the desired order 

Con la guayaba, hay una manera más limpia que la de @ LoisWasserman: utilizar Ordering combinado con Functions.forMap :

 Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)) 

o si los valores no son Comparable :

 Ordering.fromComparator(yourComparator).reverse().nullsLast().onResultOf(Functions.forMap(map, null)) 

Un ejemplo (con la primera opción – ordenamiento natural):

 final Map map = ImmutableMap.of( "key 1", "value 1", "key 2", "value 2", "key 3", "another value", "key 4", "zero value"); final Ordering naturalReverseValueOrdering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)); System.out.println(ImmutableSortedMap.copyOf(map, naturalReverseValueOrdering)); 

productos:

 {key 4=zero value, key 2=value 2, key 1=value 1, key 3=another value} 

(Yo uso ImmutableSortedMap aquí, pero TreeMap también se puede usar si se requiere mutabilidad).

EDITAR :

Si hay valores idénticos (más exactamente si hay dos valores para los cuales Comparator.compare(String v1, String v2) devuelve 0) ImmutableSortedMap arroja una excepción. El pedido no debe volver, por lo que debe ordenar primero el mapa por valores y luego las teclas si ambos valores son iguales (no se supone que las claves sean iguales) usando Ordering.compound :

 final Map map = ImmutableMap.of( "key 1", "value 1", "key 2", "value 2", "key 3", "zero value", "key 4", "zero value"); final Ordering reverseValuesAndNaturalKeysOrdering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(map, null)) // natural for values .compound(Ordering.natural()); // secondary - natural ordering of keys System.out.println(ImmutableSortedMap.copyOf(map, reverseValuesAndNaturalKeysOrdering)); 

huellas dactilares:

 {key 3=zero value, key 4=zero value, key 2=value 2, key 1=value 1} 

Método simple para obtener una copia inmutable de su mapa ordenada por valor descendente. Elimine la llamada para reverse() si desea una orden ascendente. Requiere Google Guava .

 private Map mapSortedByValues(Map theMap) { final Ordering ordering = Ordering.natural().reverse().nullsLast().onResultOf(Functions.forMap(theMap, null)); return ImmutableSortedMap.copyOf(theMap, ordering); } 

Creo que DualTreeBidiMap de Apache Commons Collections debería hacer esto posible, probablemente iterando sobre el retorno de inverseBidiMap() .

Pero no creo que esto permita valores duplicados, como su nombre lo dice, la estructura se basa simplemente en mantener dos árboles, que es realmente lo único que tiene sentido, ya que los valores en un mapa no tienen ningún significado para la estructura del mapa.

¿Qué hay de poner los valores también en TreeSet?

 for(;;) { yourMap.put(key,value); } SortedSet sortedValues = new TreeSet(yourMap.values()); 

o

 SortedSet sortedValues = new TreeSet(); for(;;) { yourMap.put(key,value); sortedValued.add(value); } 

Puse entradas en la lista y las clasifiqué. No recuerdo ningún mapa que pueda ordenarse por valores, solo por claves. Puede usar BiMap de Guava, pero requiere valores únicos.

Ejemplo:

  public static void main(String[] args) { Map map = new HashMap() {{ put("key1", "value1"); put("key2", "value3"); put("key3", "value4"); put("key4", "value2"); }}; List> entries = new ArrayList<>(map.entrySet()); Collections.sort(entries, new Comparator>() { @Override public int compare(Entry o1, Entry o2) { if (o1.getValue() == null && o2.getValue() == null) return 0; if (o1.getValue() == null) return -1; //Nulls last return - o1.getValue().compareTo(o2.getValue()); } }); } 

Creo que tienes que implementar tu propia implementación de dicho mapa. Afortunadamente, no debería ser un gran problema con Guava:

 public class SortedValueMap extends ForwardingMap { private Map delegate = newHashMap(); private Comparator valueComparator; public static > SortedValueMap reverse() { return new SortedValueMap(Ordering. natural().reverse()); } public static  SortedValueMap create(Comparator valueComparator) { return new SortedValueMap(valueComparator); } protected SortedValueMap(Comparator valueComparator) { this.valueComparator = checkNotNull(valueComparator); } @Override protected Map delegate() { return delegate; } @Override public Set keySet() { return new StandardKeySet(); } @Override public Set> entrySet() { TreeSet> result = newTreeSet(new Comparator>() { @Override public int compare(Map.Entry o1, Map.Entry o2) { return ComparisonChain.start() .compare(o1.getValue(), o2.getValue(), valueComparator) .compare(o1.getKey(), o2.getKey(), Ordering.arbitrary()) .result(); } }); result.addAll(Collections.unmodifiableMap(delegate).entrySet()); return result; } @Override public Collection values() { return new StandardValues(); } public static void main(String[] args) { SortedValueMap svm = SortedValueMap.reverse(); svm.put("foo", "1"); svm.put("bar", "3"); svm.put("baz", "2"); System.out.println(Joiner.on(", ").withKeyValueSeparator("=").join(svm)); System.out.println(Joiner.on(", ").join(svm.values())); System.out.println(Joiner.on(", ").join(svm.keySet())); } } 

Los iteradores a prueba de errores no están presentes en esta implementación; por favor añádalos si es necesario. Tenga en cuenta también que establecer un valor a través de Map.Entry.setValue causaría esgulps en el orden de clasificación, por lo que utilicé el unmodifyableMap en el conjunto de entradas.

Esto ahora se puede hacer en una sola línea usando Java 8 Streams :

 map.entrySet().stream() .sorted(Comparator.comparing(Map.Entry::getValue)) .forEach(...);