3

I want a HashMap where the keys are ordered in the way I added them.

So I am using LinkedHashMap. It has a predictable iteration order.

If you use put, the inserted key will be at the end of the map's key set.

Would it be possible to use put, inserting the key/object pair at a specific position? For instance, I'd like to put something at index 2, effectively making this pair the third entry upon iteration.

Saturn
  • 17,888
  • 49
  • 145
  • 271

4 Answers4

14

You can use a ListOrderedMap from Apache Commons Collections.

It has a put(int index, K key, V value) method that does exactly what you want.

Hyyan Abo Fakher
  • 3,497
  • 3
  • 21
  • 35
Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
  • I meant to say that a 3rd party library may provide it in my answer but I forgot. Nice to know that's out there :) – Tim B Jul 28 '14 at 10:04
5

Here is a simple method to insert a item at specific index with proper index handling using a temp map.

You can make it Generic as well.

public static void put(LinkedHashMap<String, String> input, 
                                 int index, String key, String value) {

    if (index >= 0 && index <= input.size()) {
        LinkedHashMap<String, String> output=new LinkedHashMap<String, String>();
        int i = 0;
        if (index == 0) {
            output.put(key, value);
            output.putAll(input);
        } else {
            for (Map.Entry<String, String> entry : input.entrySet()) {
                if (i == index) {
                    output.put(key, value);
                }
                output.put(entry.getKey(), entry.getValue());
                i++;
            }
        }
        if (index == input.size()) {
            output.put(key, value);
        }
        input.clear();
        input.putAll(output);
        output.clear();
        output = null;
    } else {
        throw new IndexOutOfBoundsException("index " + index
                + " must be equal or greater than zero and less than size of the map");
    }
}
Braj
  • 46,415
  • 5
  • 60
  • 76
4

None of the existing collection support that. TreeMap may do what you want by keeping the elements sorted based on the key but if you want arbitrary order then unfortunately the only way to do it would be to remove everything after that point from the map and then add them back in again.

You can emulate the behaviour you need by extending HashMap and using your own List for the iteration order. You could then expose methods to move elements around within that List. You need to be careful to keep the Map and List synchronized (as in consistent data, not as in threading) though.

Tim B
  • 40,716
  • 16
  • 83
  • 128
2

The generic version of @Braj can be found at below link.
Implementation detail is slightly different but works without trouble.

https://stackoverflow.com/a/21054277/361100

The below code is same as above link but I reflect squarefrog's comment.

public static <K, V> void add(LinkedHashMap<K, V> map, int index, K key, V value) {
  assert (map != null);
  assert !map.containsKey(key);
  assert (index >= 0) && (index < map.size());

  int i = 0;
  List<Entry<K, V>> rest = new ArrayList<Entry<K, V>>();
  for (Entry<K, V> entry : map.entrySet()) {
    if (i++ >= index) {
      rest.add(entry);
    }
  }
  map.put(key, value);
  for (int j = 0; j < rest.size(); j++) {
    Entry<K, V> entry = rest.get(j);
    map.remove(entry.getKey());
    map.put(entry.getKey(), entry.getValue());
  }
}
Community
  • 1
  • 1
Youngjae
  • 24,352
  • 18
  • 113
  • 198