Comment trier un LinkedHashMap par valeur en ordre décroissant dans java stream?

faire le tri int ordre croissant, je peux utiliser:

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue())
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Comment puis-je le faire en ordre décroissant?

12
demandé sur Misha 2015-04-25 06:29:20

4 réponses

Depuis Java 1.8 java.util.Comparateur.inversé()

myMap.entrySet().stream()
.sorted(Map.Entry.comparingByValue().reversed())
.collect(Collectors.toMap(Entry::getKey, Entry::getValue));
3
répondu Ril Dank 2016-09-16 15:55:00

Pour trier dans l'ordre inverse, pass Comparator.reverseOrder() comme paramètre comparingByValue.

Pour obtenir un LinkedHashMap, vous devez en demander un avec le 4-argument toMap(). Si vous ne spécifiez pas le type de carte que vous voulez, vous obtiendrez ce que la valeur par défaut est, ce qui se trouve être un HashMap. Depuis HashMap ne préserve pas l'ordre des éléments, il ne fera certainement pas pour vous.

myMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
        .collect(Collectors.toMap(
                Map.Entry::getKey, 
                Map.Entry::getValue, 
                (x,y)-> {throw new AssertionError();},
                LinkedHashMap::new
        ));

avec les importations statiques, il devient un peu plus agréable:

myMap.entrySet().stream()
        .sorted(comparingByValue(reverseOrder()))
        .collect(toMap(
                Map.Entry::getKey, 
                Map.Entry::getValue, 
                (x,y)-> {throw new AssertionError();},
                LinkedHashMap::new
        ));
28
répondu Misha 2016-04-21 07:05:54

vous pouvez passer n'importe quel comparateur que vous voulez comparingByValue.

Par exemple (j'espère que je suis la syntaxe droit, puisque je ne peux pas tester):

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((v1,v2)->v2.compareTo(v1)))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

En comparant les valeurs des deux entrées dans l'ordre inverse, à l'aide de l'ordre naturel (ComparablecompareTo), vous obtenez un ordre inversé par rapport à ce comparingByValue() (ce qui équivaut à comparingByValue((v1,v2)->v1.compareTo(v2))).

BTW, je ne suis pas sûr que Collectors.toMap retourne un LinkedHashMap exemple, et même si elle actuellement cela peut changer dans le futur, puisque le Javadoc ne le mentionne pas, donc vous ne pouvez pas compter dessus.

pour être sûr que la carte résultante soit une LinkedHashMap, vous devez utiliser une variante différente de toMap:

myMap.entrySet().stream()
    .sorted(Map.Entry.comparingByValue((v1,v2)->v2.compareTo(v1)))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (v1,v2)->v1, LinkedHashMap::new));
5
répondu Eran 2015-04-25 12:15:21

Stream sorted méthode qui accepte un comparateur d'où vous pouvez directement utiliser le comparateur comme (x,y)->y.getKey().compareTo(x.getKey()) pour le tri décroissant. Pour trier la carte dans ascending nous pouvons inverser l'ordre comme (x,y)->x.getKey().compareTo(y.getKey())

pour consolider le résultat dans LinkedHashMap nous pouvons utiliser des collecteurs toMap(Function<? super T,? extends K> keyMapper, Function<? super T,? extends U> valueMapper, BinaryOperator<U> mergeFunction, Supplier<M> mapSupplier) qui Renvoie un collecteur qui accumule des éléments dans une carte dont les clés et les valeurs sont le résultat de l'application des fonctions de mappage fournies à l'entrée élément.

code de travail

import java.io.*;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.*;
public class HelloWorld{

     public static void main(String []args){
        LinkedHashMap<Integer,Integer> hashMap = new LinkedHashMap<Integer,Integer>(); 
            hashMap.put(1,5);
            hashMap.put(7,9);
            hashMap.put(3,8);
            hashMap.put(10,5);

            Function<Map.Entry<Integer,Integer>,Integer> keyMapper = x->x.getKey();
            Function<Map.Entry<Integer,Integer>,Integer> valueMapper = x->x.getValue();
            BinaryOperator< Integer> mergeFunction = (x,y)->x;// we do not want any merging here 
            Supplier<LinkedHashMap<Integer,Integer>> mapRequired =()-> {return new LinkedHashMap<Integer,Integer>();};// to maintain order we must use LinkedHashMap
            Comparator<Map.Entry<Integer,Integer>> descendingComparator = (x,y)->y.getKey().compareTo(x.getKey());
            // we can write it as  

        System.out.println(
                  hashMap.entrySet().stream()
                             .sorted (descendingComparator) 
                             .collect(Collectors.toMap(
                                                      keyMapper,
                                                       valueMapper,
                                                       mergeFunction,
                                                       mapRequired)
                                           )
                );           

// or even by writing below will also work

        System.out.println(
                  hashMap.entrySet().stream()
                             .sorted ((x,y)->y.getKey().compareTo(x.getKey())) 
                             .collect(Collectors.toMap(
                                                       x->x.getKey(),
                                                       x->x.getValue(),
                                                       (x,y)->x,
                                                       LinkedHashMap::new)
                                           )
                );           
     }


}
3
répondu Shirishkumar Bari 2015-04-26 08:38:18