I have a LinkedHashMap:
LinkedHashMap<String, RecordItemElement>
that I need to iterate through from a given key's position, backwards. So if I was given the 10th item's key, I'd need iterate backwards through the hashmap 9, 8, 7 etc.
-
Do you know the keys of all items or not ?Android Killer– Android Killer08/24/2011 05:35:58Commented Aug 24, 2011 at 5:35
-
I do. Suggesting I iterate through once, add to a list, then iterate that backwards using them as keys? Suppose that would workDominic Bou-Samra– Dominic Bou-Samra08/24/2011 05:37:50Commented Aug 24, 2011 at 5:37
-
1I assume you just want to iterate in reverse in "order of insertion" here, or do you want real ordering based on some natural ordering? See also stackoverflow.com/a/1936472/32453rogerdpack– rogerdpack12/09/2015 16:38:46Commented Dec 9, 2015 at 16:38
7 Answers 7
The question requires a LinkedHashMap in reverse order, some answers suggesting using a TreeSet but this will reorder the map based upon the key.
This solution allows the iteration over the original LinkedHashMap not the new ArrayList as has also been proposed:
List<String> reverseOrderedKeys = new ArrayList<String>(linkedHashMap.keySet());
Collections.reverse(reverseOrderedKeys);
for (String key : reverseOrderedKeys) {
RecordItemElement line = linkedHashMap.get(key);
}
-
I'd personally create a
List<Entry<String, RecordItemElement>>
usingnew ArrayList<>(linkedHashMap.entrySet())
and use the entries' keys & values, rather than storing just the keys and doing a second map lookup to get the value for each key.M. Justin– M. Justin01/17/2024 16:25:04Commented Jan 17, 2024 at 16:25
The HashMap:
HashMap<Integer, String> map = new HashMap<Integer, String>();
Reverse iterating over values:
ListIterator<Sprite> iterator = new ArrayList<String>(map.values()).listIterator(map.size());
while (iterator.hasPrevious()) String value = iterator.previous();
Reverse iterating over keys:
ListIterator<Integer> iterator = new ArrayList(map.keySet()).listIterator(map.size());
while (iterator.hasPrevious()) Integer key = iterator.previous();
Reverse iterating over both:
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();
You don't have to iterate through it. But it would be handy to pull the keys off and store it in a list. Thats the only way you can do indexOf() type operations.
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)));
-
5Instead of keyList.indexOf(...) use listIterator with the position. and iterate with previous()Shimi Bandiel– Shimi Bandiel08/24/2011 05:56:54Commented Aug 24, 2011 at 5:56
-
Instead of keyList.indexOf(...) use keyList.size()-1Óscar López– Óscar López01/17/2012 11:09:07Commented Jan 17, 2012 at 11:09
-
7@Kal The operation of your solution is O(n), which is well.. horrible.Pacerier– Pacerier02/23/2012 18:08:48Commented Feb 23, 2012 at 18:08
-
Well doing so you create unnecessary overhead by copying the key set. Consider using TreeMap.Anton– Anton05/07/2012 15:55:40Commented May 7, 2012 at 15:55
-
3The
LinkedHashMap#keySet()
returns aSet
backed by aLinkedKeySet
, which is a nested class with package-local visibility. The iteration order is defined by itsSpliterator
, which is ordered in the same order as the map entries. So, in this case, the order IS guaranteed.Chthonic Project– Chthonic Project06/27/2015 20:34:46Commented Jun 27, 2015 at 20:34
new LinkedList(linkedHashMap.keySet()).descendingIterator();
As of Java 21, LinkedHashMap
has the reversed()
method, which returns a reversed view of the map. This can be iterated over in the standard manner.
myLinkedHashMap.reversed().forEach((key, value) -> {
// Do something with the key and/or value
});
To specifically start with a given key as requested, a Stream
over the reversed map's entry set could be used, using the dropWhile
method to skip all elements encountered prior to that key:
String matchingKey = "someKey";
myLinkedHashMap.entrySet().stream()
.dropWhile(e -> !matchingKey.equals(e.getKey()))
.forEach(e -> {
String key = e.getKey();
RecordItemElement value = e.getValue();
// Do something with key & value
});
Using "user22745008" solution and labdas with some generics you can have a very neat solution as a method:
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;
}
This is an old question, but I think it's lacking an answer that takes a newer approach. The following uses Java 9 features:
Deque<Map.Entry<String, RecordItemElement>> top = map.entrySet().stream()
.takeWhile(e -> !givenKey.equals(e.getKey()))
.collect(Collectors.toCollection(ArrayDeque::new));
The code above streams the map's entryset, keeping entries until a key equal to the given key is found. Then, the entries are collected to an ArrayDeque
.
One detail is missing, though. Depending on whether you need the entry that matches the given key to also be included in the result or not, you might need to manually add it to the deque. If you don't want it added, then you're done. Otherwise, simply do:
top.add(Map.entry(givenKey, map.get(givenKey)));
Now, to iterate the Deque
in reverse order, simply use its descendingIterator()
:
Iterator<Map.Entry<String, RecordItemElement>> descIt = top.descendingIterator();
It's worth mentioning that this approach only works if the stream is sequential. Anyways, we wouldn't have gained anything using a parallel stream here.