user291701
user291701

Reputation: 39681

Iterate to find a Map entry at an index?

I have a LinkedHashMap. I want to get the Foo at index N. Is there a better way of doing this besides iterating until I find it?:

int target = N;
int index = 0;
for (Map.Entry<String, Foo> it : foos.entrySet()) {
    if (index == target) {
        return it.getValue();
    }
    index++;
}

I have to do get random elements from the map by an index about 50 times for some operation. The map will have about 20 items in it.

Thanks

Upvotes: 11

Views: 14920

Answers (4)

Stephen C
Stephen C

Reputation: 718886

@Mark's solution is spot on. I'd just like to point out that the offsets (positions) of the entries in a map (of any kind) are not stable. Each time an entry is added or removed, the offsets of the remaining entries may change. For a HashMap or LinkedHashMap, you've no way of knowing which entry's offsets will change.

  • For a regular HashMap, a single insertion can apparently "randomize" the entry offsets.
  • For a LinkedHashMap, the order of the entries is stable, the actual entry offsets are not.

The instability of the offsets and the fact that finding entry at a given offset is expensive for all standard map implementations are the reasons why the Map interface does not provide a get(int offset) method. It should also be a hint that it is not a good idea for an algorithm to need to do this sort of thing.

Upvotes: 3

Alex K
Alex K

Reputation: 22857

Guava library can help in this case:

public static <T> T com.google.common.collect.Iterables.get(Iterable<T> iterable, int position)

see javadoc: Iterables.get

For your case the code can be like this:

Iterables.get(foos.values(), N);

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533530

A simplification of @Mark's solution... You only need the values, so each time you change a value in the foos Map, also update an array.

Map<String, Foo> foos =;
Foo[] fooValues = {};

foos.put(foos.name(), foo);
fooValues = foos.values().toArray(new Foo[foos.size()]);

// later
Foo foo = fooValues[N];

Upvotes: 0

Mark Elliot
Mark Elliot

Reputation: 77044

List<Entry<String,Foo>> randAccess = new ArrayList<Entry<String,Foo>>(foos.entrySet());

Then for index N with O(1) access...

randAccess.get(N)

Upvotes: 14

Related Questions