3
votes

Java Tri d'une carte à l'aide de Steams VS TreeMap

Considérez le HashMap Java suivant:

Map<String, Integer> sortedMap = new HashMap<>();
unsortMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey())
    .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

Maintenant, je souhaite trier cette carte par clé. Une option est pour moi d'utiliser un TreeMap à cette fin.

Map<String, String> treeMap = new TreeMap<String, String>(unsortMap);

Une autre option est pour moi d'utiliser les flux Java avec Sorted (), comme suit.

XXX

Parmi ces deux options, quelle option est préférée et pourquoi (peut-être en termes de performances)?

Merci


4 commentaires

Votre deuxième option ne fonctionne pas réellement. Cela devrait sûrement y aller?


Ma compréhension sur HashMaps et LinkedHashMaps était faible. Je l'ai obtenu dans cet article, qui a en fait la bonne implémentation howtodoinjava.com/ sort / java-sort-map-by-key


Avec le commentaire ci-dessus, veuillez expliquer quelle option est bien meilleure? TreeMap de LinkedHashMap tri via les flux


Des pommes aux oranges ... ce ne sont pas la même structure de données


3 Réponses :


1
votes

Votre code de flux ne triera même pas la carte, car il exécute l'opération sur un HashMap , qui n'est pas trié par nature. Pour faire fonctionner votre deuxième exemple de flux, vous pouvez utiliser LinkedHashMap , qui maintient l'ordre d'insertion:

Map<String, Integer> sortedMap = new LinkedHashMap<>();
unsortMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey())
    .forEachOrdered(x -> sortedMap.put(x.getKey(), x.getValue()));

Mais maintenant, vos deux exemples ne sont même pas la même structure de données sous-jacente. Un TreeMap est soutenu par un arbre (rouge noir si je me souviens bien). Vous utiliseriez une TreeMap si vous vouliez pouvoir itérer de manière triée, ou rechercher rapidement une clé. Un LinkedHashMap est un hashmap avec une liste liée qui le traverse. Vous l'utiliseriez si vous deviez maintenir l'ordre d'insertion, par exemple lors de la mise en œuvre d'une file d'attente.


0 commentaires

1
votes

La deuxième méthode ne fonctionne pas, lorsque vous appelez HashMap # put , il ne maintient pas l'ordre de mise. Vous aurez peut-être besoin de LinkedHashMap .

TreeMap v.s. Stream (LinkedHashMap):

  1. style de code. L'utilisation de TreeMap est plus propre car vous pouvez y parvenir en une seule ligne.
  2. complexité spatiale. Si la carte d'origine est HashMap , avec les deux méthodes, vous devez créer une nouvelle carte . Si la carte d'origine est LinkedHashMap , il vous suffit de créer une nouvelle carte avec la première approche. Vous pouvez réutiliser le LinkedHashMap avec la deuxième approche.
  3. complexité temporelle. Ils devraient tous les deux avoir O (nln (n)).

0 commentaires

2
votes

Comme d'autres l'ont souligné, le vidage du flux trié d'entrées dans un HashMap normal ne ferait rien ... LinkedHashMap est le choix logique.

Cependant, un Une alternative aux approches ci-dessus consiste à utiliser pleinement l'API Stream Collectors .

Collectors a une méthode toMap qui vous permet de fournir une implémentation alternative pour la Map . Ainsi au lieu d'un HashMap vous pouvez demander un LinkedHashMap comme ceci:

unsortedMap.entrySet()
    .stream()
    .sorted(Map.Entry.comparingByKey())
    .collect(Collectors.toMap(
       Map.Entry::getKey,
       Map.Entry::getValue,
       (v1, v2) -> v1, // you will never merge though ask keys are unique.
       LinkedHashMap::new
    ));

Entre l'utilisation d'un TreeMap vs LinkedHashMap. .. La complexité de la construction est probablement la même chose que O (n log n) ... De toute évidence, la solution TreeMap est une meilleure approche si vous prévoyez de continuer à y ajouter plus d'éléments. Je suppose que vous auriez dû commencer avec un TreeMap dans ce cas. L'option LinkedHashMap a l'avantage que la recherche sera O (1) sur la carte liée ou non triée d'origine alors que TreeMap est quelque chose comme O (log n) donc si vous avez besoin de conserver la carte non triée pour une recherche efficace, alors que si vous construisez la LinkedHashMap, vous pouvez jeter la carte originale non triée (économisant ainsi de la mémoire).

Pour rendre les choses un peu plus efficaces avec LinkedHashMap vous devez fournir un bon estimateur de la taille requise lors de la construction afin qu'il n'y ait pas besoin de redimensionnement dynamique, donc au lieu de LinkedHashMap :: new vous dites () -> nouveau LinkedHashMap (unsortedMap.size ()) .

Je suis d'avis que l'utilisation d'un TreeMap est plus soignée ... car elle réduit la taille du code, à moins qu'il n'y ait un problème de performances réel qui pourrait être résolu en utilisant le non trié et approche de carte liée triée J'utiliserais l 'Tree .


3 commentaires

Ajouter à cela les placer dans un hashmap ne ferait rien car il insérera simplement les données dans un ordre aléatoire à nouveau.


@SanathKumar ... pas sûr de ce que vous voulez dire ... la solution utilise un LinkedHashMap pas un HashMap normal.


J'essayais d'expliquer pourquoi l'utilisation d'un hashmap ne fonctionnerait pas. C'était destiné à op pas vous.