Carte pouvant être itérée dans l’ordre des valeurs

J’ai besoin d’une carte qui pourrait être itérée dans l’ ordre décroissant de ses valeurs . Est-ce que des bibliothèques standard comme Apache Commons ou Guava fournissent ce type de carte?

Je le ferais avec Guava comme suit:

 Ordering> entryOrdering = Ordering.from(valueComparator) .onResultOf(new Function, Value>() { public Value apply(Entry entry) { return entry.getValue(); } }).reverse(); // Desired ensortinges 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 ensortinges in the desired order 

Avec la goyave, il y a une manière encore plus propre que la réponse de @ LoisWasserman – en utilisant la commande combinée avec Functions.forMap :

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

ou si les valeurs ne sont pas Comparable :

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

Un exemple (avec première option – classement naturel):

 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)); 

les sorties:

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

(J’utilise ImmutableSortedMap ici, mais TreeMap peut également être utilisé si une mutabilité est requirejse.)

EDIT :

S’il existe des valeurs identiques (plus exactement si il y a deux valeurs pour lesquelles Comparator.compare(Ssortingng v1, Ssortingng v2) renvoie 0), ImmutableSortedMap lève une exception. La commande ne doit pas être renvoyée, c.-à-d. Que vous devez d’abord ordonner la carte par les valeurs et les clés suivantes si les deux valeurs sont égales (les clés ne sont pas supposées être égales) en utilisant 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)); 

impressions:

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

Méthode simple pour obtenir une copie immuable de votre carte sortingée par valeur décroissante. Supprimez l’appel à reverse() si vous souhaitez un ordre croissant. Nécessite Google Guava .

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

Je pense que le DualTreeBidiMap de Apache Commons Collections devrait rendre cela possible, probablement en itérant sur le retour de inverseBidiMap() .

Mais je ne pense pas que cela permette de dupliquer les valeurs – comme son nom l’indique, la structure est simplement basée sur la conservation de deux arbres, ce qui est vraiment la seule chose qui ait du sens, car les valeurs dans une carte n’ont aucune signification pour la structure de la carte.

Qu’en est-il de mettre les valeurs également dans TreeSet?

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

ou

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

Je mettrais des entrées sur la liste et la sortingerais. Je ne me souviens d’aucune carte pouvant être ordonnée par des valeurs, mais uniquement par des clés. Vous pouvez utiliser BiMap from Guava, mais cela nécessite des valeurs uniques.

Exemple:

  public static void main(Ssortingng[] args) { Map map = new HashMap() {{ put("key1", "value1"); put("key2", "value3"); put("key3", "value4"); put("key4", "value2"); }}; List> ensortinges = 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()); } }); } 

Je pense que vous devez déployer votre propre implémentation d’une telle carte. Heureusement, Guava ne devrait pas poser trop de problèmes:

 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(Ssortingng[] 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())); } } 

Les iterators rapides ne sont pas présents dans cette implémentation; veuillez les append vous-même si nécessaire. Veuillez également noter que la définition d’une valeur via Map.Entry.setValue provoquerait des dégâts avec l’ordre de sorting, raison pour laquelle j’ai utilisé unmodifyableMap dans le jeu d’entrées.

Cela peut maintenant être fait en une seule ligne en utilisant Java 8 Streams :

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