IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Collection et Stream Java Discussion :

Trier une Map sur les valeurs de façon décroissante


Sujet :

Collection et Stream Java

  1. #1
    Membre habitué Avatar de ddams
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2002
    Messages : 147
    Points : 148
    Points
    148
    Par défaut Trier une Map sur les valeurs de façon décroissante
    Bonjour,

    J'ai besoin de trier une map sur les valeurs de façon décroissante.
    La clé est un String.
    La valeur est un Integer.

    Comment procéder ?

    merci d'avance.
    @+ddams

  2. #2
    Expert éminent
    Avatar de elitost
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2003
    Messages
    1 985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 985
    Points : 6 566
    Points
    6 566
    Par défaut
    En implémentant une classe Comparator comme ceci :

    A adapter bien sûr :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class CollectionComparator {
      static final Comparator ORDRE_DATE = new Comparator() {
        public int compare(Object o1, Object o2){
          if(!(o1 instanceof Video))
            throw new ClassCastException();
          return (new Integer(((Video)o1).obtenirAnnee())).compareTo(
                            new Integer(((Video)o2).obtenirAnnee()));
        }
      };
      static final Comparator ORDRE_REALISATEUR = new Comparator() {
        public int compare(Object o1, Object o2){
          if(!(o1 instanceof Video))
            throw new ClassCastException();
          return (((Video)o1).obtenirRealisateur()).compareTo(
                            ((Video)o2).obtenirRealisateur());
        }
      };
      public static void main(String[] args) {
        TreeSet t = new TreeSet();
        t.add(new Video("Le jour le plus long", "Ken Annakin", 1962));
        t.add(new Video("Un pont trop loin", "Richard Attenborough", 1977));
        t.add(new Video("Platoon", "Oliver Stone", 1986));
        t.add(new Video("Full metal jacket", "Stanley Kubrik", 1987));
        t.add(new Video("La ligne rouge", "Terrence Malick", 1998));
        t.add(new Video("The patriot", "Roland Emmerich", 2000));
        System.out.println("Tri par titre :\n" + t);    
        TreeSet tr = new TreeSet(ORDRE_REALISATEUR);
        tr.addAll(t);
        System.out.println("\nTri par réalisateur :\n" + tr);
        TreeSet ta = new TreeSet(ORDRE_DATE);
        ta.addAll(t);
        System.out.println("\nTri par année :\n" + ta);
     
      }
    }
    Bon courage

  3. #3
    Membre habitué Avatar de ddams
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2002
    Messages : 147
    Points : 148
    Points
    148
    Par défaut
    merci pour ta réponse elitost,

    Je test ça ce soir.
    @+ddams

  4. #4
    Expert éminent
    Avatar de elitost
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2003
    Messages
    1 985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 985
    Points : 6 566
    Points
    6 566
    Par défaut
    A noter que la solution que je te donne est à adapter.

  5. #5
    Membre habitué Avatar de ddams
    Profil pro
    Inscrit en
    Mars 2002
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mars 2002
    Messages : 147
    Points : 148
    Points
    148
    Par défaut
    Merci elitost,

    Ton code m'a bien aidé.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    private static Map sortMap(Map aMap) {
        Map myMap = new HashMap();
        TreeSet set = new TreeSet(new Comparator(){
            public int compare(Object obj, Object obj1) {
    	Integer val1 = (Integer) ((Map.Entry) obj).getValue();
    	Integer val2 = (Integer) ((Map.Entry) obj1).getValue();
                    return val1.compareTo(val2);
            }	
        });
     
       set.addAll(aMap.entrySet());
     
        for(Iterator it = set.iterator(); it.hasNext() ;) {
            Map.Entry myMapEntry = (Map.Entry) it.next();
            myMap.put(myMapEntry.getKey(), myMapEntry.getValue());
        }
     
        return myMap; 
    }
    @+ddams

  6. #6
    Expert éminent
    Avatar de elitost
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Septembre 2003
    Messages
    1 985
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Septembre 2003
    Messages : 1 985
    Points : 6 566
    Points
    6 566
    Par défaut
    C'est bien si ça fonctionne alors.

    Bon courage

  7. #7
    Membre du Club
    Inscrit en
    Juin 2006
    Messages
    53
    Détails du profil
    Informations forums :
    Inscription : Juin 2006
    Messages : 53
    Points : 40
    Points
    40
    Par défaut
    Bonjour,

    J'ai essayé de reprendre votre code car je voudrais trier une Map de façon croissante mais j'ai un petit soucis !!

    Voici mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
        private void sortMap(Map aMap) {
            Map myMap = new HashMap();
            Set set = new TreeSet(
                new Comparator()
                {
                    public int compare(Object obj, Object obj1)
                    {
                        Integer val1 = (Integer) ((Map.Entry) obj).getValue();
                        Integer val2 = (Integer) ((Map.Entry) obj1).getValue();
                        if (val2.compareTo(val1)==0) return -1;
                        return val2.compareTo(val1);
                    }   
                }
            );
     
            set.addAll(aMap.entrySet());
     
            for(Iterator it = set.iterator(); it.hasNext() ;) {
                Map.Entry myMapEntry = (Map.Entry) it.next();
                System.out.println (  myMapEntry.getKey (  )  + " = " + myMapEntry.getValue (  )   ) ; 
                myMap.put( myMapEntry.getKey(), myMapEntry.getValue());
            }
     
            System.out.println("MyMap: "+myMap.values());
     
        }
    Mon probleme est que les deux lignes suivantes ne me donne pas le même résultat:

    System.out.println (myMapEntry.getKey()+"="+myMapEntry.getValue()) ;

    System.out.println("MyMap: "+myMap.values());

    En effet, la premiere ligne me donne les résultats dans l'ordre croissant comme je le désire, alors que la deuxieme me donne les résultats dans le sens inverse (en faite elle me donne le résultats toujours dans l'ordre décroissant)

    Je ne comprend pas d'ou vient cette erreur. On dirait que la fonction "put" met les réultats toujours dans le même ordre.

    Il est également fortement possible que j'ai mal compris le code, en effet je ne suis pas familier avec les comparator.

    Pourriez-vous m'aider s'il vous plait.

    Merdi beaucoup pour votre aide.

  8. #8
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Avril 2009
    Messages
    52
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2009
    Messages : 52
    Points : 40
    Points
    40
    Par défaut
    Bonjour,

    Moi aussi j'ai essayé le code et ça marche pas est ce que vous pouvez m'aider.
    En fait je pense que ça marche que sur le key.


    Merci de votre aide.

  9. #9
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Décembre 2011
    Messages
    1
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1
    Points : 1
    Points
    1
    Par défaut Et si on a des valeur double ??
    Bonjour,

    J'ai le même problème. J'ai réussi à en résoudre une partie mon problème c'est que dans mon HashMap peux posseder des clés différentes mais les même valeurs du coups votre méthode ne marche plus. Quelqu'un a une idée ??

    Voila mon code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    import java.util.*;
    import java.lang.*;
     
    public class test {
     
        public static void main(String[] args) {
     
            Map< String, Integer> tm = new HashMap< String, Integer>();
            tm.put("A", new Integer(3));
            tm.put("B", new Integer(1));
            tm.put("C", new Integer(3));
            tm.put("D", new Integer(5));
            Map myMap = new HashMap();
            TreeSet set = new TreeSet(new Comparator(){
                public int compare(Object obj, Object obj1) {
    	        Integer val1 = (Integer) ((Map.Entry) obj).getValue();
    	        Integer val2 = (Integer) ((Map.Entry) obj1).getValue();
                        return val1.compareTo(val2);
                }	
            });
     
           set.addAll(tm.entrySet());
     
           for(Iterator it = set.iterator(); it.hasNext() ;) {
                Map.Entry myMapEntry = (Map.Entry) it.next();
                System.out.println(myMapEntry.getKey() + " " + myMapEntry.getValue());
                myMap.put(myMapEntry.getKey(), myMapEntry.getValue());
           }
     
        }
     
    }
    Résultat :

    B 1
    A 3
    D 5


    ??

  10. #10
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Dans ce cas il faut insérer les éléments dans une List au lieu d'un Set.

    Et comme une List ne se trie pas toute seule, il faut la faire trier en appelant Collections.sort() en lui passant la List à trier et le Comparator à utiliser.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Membre émérite
    Homme Profil pro
    Développeur Java/Scala
    Inscrit en
    Octobre 2007
    Messages
    1 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Scala

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 086
    Points : 2 271
    Points
    2 271
    Par défaut
    Je ne suis pas trop d'accord avec les codes précédemment donnés!

    Une HashMap est une map non ordonnée, et non triée.


    Non ordonnée: quand vous iterez dessus, vous n'êtes pas sur de retrouver les éléments dans le même ordre que celui d'insertion (l'ordre dépend du hashcode des objets)

    Non triée: si vous insérez 1 3 6 4 5 6, ils ne seront pas automatiquement ordonnés par valeur croissante/décroissante (ou autre selon le comparator).


    Bref si vous utilisez une hashmap en sortie de votre fonction, vous ne pourrez pas être certain de l'ordre!



    Votre code devrait marcher avec une Map ordonnée telle que la LinkedHashMap si vous utilisez une:
    http://docs.oracle.com/javase/1.4.2/...edHashMap.html


    Ca aurait été cool de pouvoir utiliser une TreeMap, qui elle est une map triée, mais seulement sur les clés et non les valeurs...

    Le problème est posé depuis longtemps, et il existe plusieurs solutions possibles détaillées ici:
    http://stackoverflow.com/questions/1...420912#3420912
    React-Hebdo - Newsletter pour se tenir à jour sur l'écosystème React

  12. #12
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par HerQuLe Voir le message
    Bref si vous utilisez une hashmap en sortie de votre fonction, vous ne pourrez pas être certain de l'ordre!

    Votre code devrait marcher avec une Map ordonnée telle que la LinkedHashMap
    C'est mieux qu'une autre Map, mais bon, moi je dis si on veut un ordre précis, on utilise une structure qui conserve cet ordre précis. D'où l'idée de mettre les valeurs dans une List pour avoir les éléments triés dans l'ordre.
    Et de garder la Map quand on veut vérifier les associations clé/valeur.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  13. #13
    Membre émérite
    Homme Profil pro
    Développeur Java/Scala
    Inscrit en
    Octobre 2007
    Messages
    1 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Scala

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 086
    Points : 2 271
    Points
    2 271
    Par défaut
    En fait j'avais mal lu le code de elitost/ddams/linchan39 etc et , je pensais qu'ils ajoutaient juste les valeurs dans le set et les triaient pour finir par récupérer la clé associée dans la map (ce qui pose problème si les valeurs ne sont pas uniques forcement...).


    Cependant le code suivant n'est pas totalement bon (en plus de ne pas utiliser les générics).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    private static Map sortMap(Map aMap) {
        Map myMap = new HashMap();
        TreeSet set = new TreeSet(new Comparator(){
            public int compare(Object obj, Object obj1) {
    	Integer val1 = (Integer) ((Map.Entry) obj).getValue();
    	Integer val2 = (Integer) ((Map.Entry) obj1).getValue();
                    return val1.compareTo(val2);
            }	
        });
     
       set.addAll(aMap.entrySet());
     
        for(Iterator it = set.iterator(); it.hasNext() ;) {
            Map.Entry myMapEntry = (Map.Entry) it.next();
            myMap.put(myMapEntry.getKey(), myMapEntry.getValue());
        }
     
        return myMap; 
    }
    En effet, une fois les map entries triées dans le set, elles sont rajoutées dans une hashmap qui peut potentiellement les réorganiser comme elle veut!)



    Citation Envoyé par thelvin Voir le message
    C'est mieux qu'une autre Map, mais bon, moi je dis si on veut un ordre précis, on utilise une structure qui conserve cet ordre précis. D'où l'idée de mettre les valeurs dans une List pour avoir les éléments triés dans l'ordre.
    Et de garder la Map quand on veut vérifier les associations clé/valeur.

    Pas du tout
    On peut le faire également mais comme tu dis toi même, une liste ne se trie pas toute seule... à la différence d'un SortedSet (TreeSet) qui lui oui et restera toujours ordonné sans avoir besoin d'appeler une méthode.




    Bref voici une solution avec les explications dans le code:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
     
        public static void main(String[] args) {
     
            // If you want to sort a map by value, and if there can be twice the same value:
     
            // here is your original map
            Map<String,Integer> mapToSortByValue = new HashMap<String, Integer>();
            mapToSortByValue.put("A", 3);
            mapToSortByValue.put("B", 1);
            mapToSortByValue.put("C", 3);
            mapToSortByValue.put("D", 5);
            mapToSortByValue.put("E", -1);
            mapToSortByValue.put("F", 1000);
            mapToSortByValue.put("G", 79);
            mapToSortByValue.put("H", 15);
     
            // Sort all the map entries by value
            Set<Map.Entry<String,Integer>> set = new TreeSet<Map.Entry<String,Integer>>(
                    new Comparator<Map.Entry<String,Integer>>(){
                        @Override
                        public int compare(Map.Entry<String,Integer> obj1, Map.Entry<String,Integer> obj2) {
                            Integer val1 = obj1.getValue();
                            Integer val2 = obj2.getValue();
                            // DUPLICATE VALUE CASE
                            // If the values are equals, we can't return 0 because the 2 entries would be considered
                            // as equals and one of them would be deleted (because we use a set, no duplicate, remember!)
                            int compareValues = val1.compareTo(val2);
                            if ( compareValues == 0 ) {
                                String key1 = obj1.getKey();
                                String key2 = obj2.getKey();
                                int compareKeys = key1.compareTo(key2);
                                if ( compareKeys == 0 ) {
                                    // what you return here will tell us if you keep REAL KEY-VALUE duplicates in your set
                                    // if you want to, do whatever you want but do not return 0 (but don't break the comparator contract!)
                                    return 0;
                                }
                                return compareKeys;
                            }
                            return compareValues;
                        }
                    }
            );
            set.addAll(mapToSortByValue.entrySet());
     
     
            // OK NOW OUR SET IS SORTED COOL!!!!
     
            // And there's nothing more to do: the entries are sorted by value!
            for ( Map.Entry<String,Integer> entry : set ) {
                System.out.println("Set entries: " + entry.getKey() + " -> " + entry.getValue());
            }
     
     
     
     
            // But if you add them to an hashmap
            Map<String,Integer> myMap = new HashMap<String,Integer>();
            // When iterating over the set the order is still good in the println...
            for ( Map.Entry<String,Integer> entry : set ) {
                System.out.println("Added to result map entries: " + entry.getKey() + " " + entry.getValue());
                myMap.put(entry.getKey(), entry.getValue());
            }
     
            // But once they are in the hashmap, the order is not kept!
            for ( Integer value : myMap.values() ) {
                System.out.println("Result map values: " + value);
            }
            // Also this way doesn't work:
            // Logic because the entryset is a hashset for hashmaps and not a treeset
            // (and even if it was a treeset, it would be on the keys only)
            for ( Map.Entry<String,Integer> entry : myMap.entrySet() ) {
                System.out.println("Result map entries: " + entry.getKey() + " -> " + entry.getValue());
            }
     
     
            // CONCLUSION:
            // If you want to iterate on a map ordered by value, you need to remember:
            // 1) Maps are only sorted by keys, so you can't sort them directly by value
            // 2) So you simply CAN'T return a map to a sortMapByValue function
            // 3) You can't reverse the keys and the values because you have duplicate values
            //    This also means you can't neither use Guava/Commons bidirectionnal treemaps or stuff like that
     
            // SOLUTIONS
            // So you can:
            // 1) only sort the values which is easy, but you loose the key/value link (since you have duplicate values)
            // 2) sort the map entries, but don't forget to handle the duplicate value case (like i did)
        }
    Le code executé ici:
    http://www.ideone.com/dq3Lu


    Donne en sortie:

    Set entries: E -> -1
    Set entries: B -> 1
    Set entries: A -> 3
    Set entries: C -> 3
    Set entries: D -> 5
    Set entries: H -> 15
    Set entries: G -> 79
    Set entries: F -> 1000
    Added to result map entries: E -1
    Added to result map entries: B 1
    Added to result map entries: A 3
    Added to result map entries: C 3
    Added to result map entries: D 5
    Added to result map entries: H 15
    Added to result map entries: G 79
    Added to result map entries: F 1000
    Result map values: 5
    Result map values: -1
    Result map values: 1000
    Result map values: 79
    Result map values: 3
    Result map values: 1
    Result map values: 3
    Result map values: 15
    Result map entries: D -> 5
    Result map entries: E -> -1
    Result map entries: F -> 1000
    Result map entries: G -> 79
    Result map entries: A -> 3
    Result map entries: B -> 1
    Result map entries: C -> 3
    Result map entries: H -> 15


    Le principal piège ici est de croire qu'une map conserve l'ordre d'insertion.
    Et je me suis moi même fait piegé par le return 0 quand on compare 2 int dans le set... du coup les valeurs en double sont effacées du set car on considère que les deux entries comparées sont égales...
    React-Hebdo - Newsletter pour se tenir à jour sur l'écosystème React

  14. #14
    Membre émérite
    Homme Profil pro
    Développeur Java/Scala
    Inscrit en
    Octobre 2007
    Messages
    1 086
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Scala

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 086
    Points : 2 271
    Points
    2 271
    Par défaut
    Oups pardon, si on veut a tout prix avoir les résultats sous forme de map, il faut ajouter les éléments dans une LinkedHashMap qui conserve l'ordre d'insertion lors de l'itération.
    React-Hebdo - Newsletter pour se tenir à jour sur l'écosystème React

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Filtrer une liste sur les valeurs d'une colonne
    Par julien.63 dans le forum SharePoint
    Réponses: 3
    Dernier message: 13/02/2009, 08h43
  2. Trier une map sur valeur int
    Par totoche dans le forum Collection et Stream
    Réponses: 9
    Dernier message: 09/05/2008, 11h54
  3. trier une hashtable selon les valeurs
    Par Raylemon dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 20/06/2007, 11h44
  4. [C#] Trier une Hashtable par les valeurs
    Par Joad dans le forum ASP.NET
    Réponses: 4
    Dernier message: 25/04/2005, 16h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo