web-dev-qa-db-fra.com

Itération dans un LinkedHashMap dans l'ordre inverse

J'ai un LinkedHashMap:

LinkedHashMap<String, RecordItemElement>

que je dois parcourir à partir de la position d'une clé donnée, à l'envers. Donc, si on me donnait la clé du 10ème élément, il me faudrait parcourir à nouveau la hashmap 9, 8, 7, etc.

32
Dominic Bou-Samra

Vous n'avez pas à parcourir cela. Mais il serait utile de retirer les clés et de les stocker dans une liste. C'est la seule façon de faire des opérations de type indexOf ().

List<String> keyList = new ArrayList<String>(map.keySet());
// Given 10th element's key
String key = "aKey";
int idx = keyList.indexOf(key);
for ( int i = idx ; i >= 0 ; i-- ) 
 System.out.println(map.get(keyList.get(i)));
7
Kal

La question nécessite un LinkedHashMap dans l'ordre inverse, certaines réponses suggérant l'utilisation d'un TreeSet, mais cela réorganisera la carte en fonction de la clé.

Cette solution permet l'itération sur le LinkedHashMap d'origine et non sur le nouvel ArrayList comme cela a également été proposé:

List<String> reverseOrderedKeys = new ArrayList<String>(linkedHashMap.keySet());
Collections.reverse(reverseOrderedKeys);
for (String key : reverseOrderedKeys) {
    RecordItemElement line = linkedHashMap.get(key);
}
9
user2274508

Le HashMap:

HashMap<Integer, String> map = new HashMap<Integer, String>();

Pour les itérations inverses sur les valeurs:

ListIterator<Sprite> iterator = new ArrayList<String>(map.values()).listIterator(map.size());
while (iterator.hasPrevious()) String value = iterator.previous();

Pour une itération inverse sur les touches:

ListIterator<Integer> iterator = new ArrayList(map.keySet()).listIterator(map.size());
while (iterator.hasPrevious()) Integer key = iterator.previous();

Pour une itération inverse sur les deux:

ListIterator<Map.Entry<Integer, String>> iterator = new ArrayList<Map.Entry<Integer, String>>(map.entrySet()).listIterator(map.size());
while (iterator.hasPrevious()) Map.Entry<Integer, String> entry = iterator.previous();
9
Ali

En utilisant la solution "user22745008" et les labdas avec certains génériques, vous pouvez avoir une solution très soignée comme méthode:

  public static <T, Q> LinkedHashMap<T, Q> reverseMap(LinkedHashMap<T, Q> toReverse)
  {
      LinkedHashMap<T, Q> reversedMap = new LinkedHashMap<>();
      List<T> reverseOrderedKeys = new ArrayList<>(toReverse.keySet());
      Collections.reverse(reverseOrderedKeys);
      reverseOrderedKeys.forEach((key)->reversedMap.put(key,toReverse.get(key)));
      return reversedMap;
    }
0
Hernanibus

C'est une vieille question, mais je pense qu'il manque une réponse qui prend une approche plus récente. Les fonctionnalités suivantes utilisent Java 9:

Deque<Map.Entry<String, RecordItemElement>> top = map.entrySet().stream()
        .takeWhile(e -> !givenKey.equals(e.getKey()))
        .collect(Collectors.toCollection(ArrayDeque::new));

Le code ci-dessus diffuse l'entrée entry de la carte, en conservant les entrées jusqu'à ce qu'une clé égale à la clé donnée soit trouvée. Ensuite, les entrées sont collectées dans une ArrayDeque.

Un détail manque cependant. Selon que vous souhaitiez ou non que l'entrée qui correspond à la clé donnée soit également incluse dans le résultat, vous devrez peut-être l'ajouter manuellement au deque. Si vous ne voulez pas l'ajouter, alors vous avez terminé. Sinon, faites simplement:

top.add(Map.entry(givenKey, map.get(givenKey)));

Maintenant, pour itérer la Deque dans l’ordre inverse, utilisez simplement sa descendingIterator():

Iterator<Map.Entry<String, RecordItemElement>> descIt = top.descendingIterator();

Il est à noter que cette approche ne fonctionne que si le flux est séquentiel . De toute façon, nous n'aurions rien gagné en utilisant un flux parallèle ici.