0

I have a TreeMap like so:

{
    "one": "First option",
    "two": "Second option",
    "three": "Third option",
    "four": "Last option"
}

I want to resort this object so that the output is like this:

{
    "four": "First option",
    "three": "Second option",
    "two": "Third option",
    "one": "Last option"
}

I was looking at some of the commons collections utilities from apache, but did not see anything immediately that would do the trick.

What is the cleanest way to write this without a bunch of loops?

Barry Chapman
  • 6,690
  • 3
  • 36
  • 64

3 Answers3

1

I think that you can only use a LinkedHashMap to store such a list, because it is not in alphabetical order. But LinkedHashMap keeps the order in which the elements have been added, so would be fine.

I do not think anything can be done much simpler than putting all map entries (obtainable via entrySet() method) into ArrayList and then adding them to another map in the reverse order, by iterating through this array. If it would be reverse iterators, we could derive a class that swaps them, but looks like there are no iterators that would move in reverse order, so overriding is not an option.

Changing the hash code of the keys after the map is created will not change the order because the buckets are already there. It, however, likely will prevent the map from working properly.

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
0

This means your mapping function (How Map is generated in first place) is wrong.

Irrespective of which Map implementation you use, it is suitable data structure to hold a key - value pair. It makes no sense to go against the basic principle of this Data Structure by distorting the key-value pairs by reversing/shuffling the keys with different values.

In this case, if the Key-Value and loosely related, we can think of holding this in two different List? Map it again as and when required as per requirement.

Also, three will be placed before two in your TreeMap. Isn't that how it is organized*?

Mohamed Anees A
  • 4,119
  • 1
  • 22
  • 35
0

Reversing the order of the keys in the map is the same as creating a new map. To do this, first create a list containing the entries of the current map, then iterate over that list in both directions at once and collect a new map. This is enough for LinkedHashMap, and for TreeMap you have to additionally specify a reversed comparator to the one that was before. Example:

  1. TreeMap

    TreeMap<Integer, String> map1 =
            new TreeMap<>(Comparator.naturalOrder()) {{
                put(1, "First option");
                put(2, "Second option");
                put(3, "Third option");
                put(4, "Last option");
            }};
    
    List<Map.Entry<Integer, String>> list1 = new ArrayList<>(map1.entrySet());
    
    TreeMap<Integer, String> map2 = IntStream.range(0, list1.size())
            .boxed().collect(Collectors.toMap(
                    // from the end to the beginning
                    i -> list1.get(list1.size() - i - 1).getKey(),
                    // from the beginning to the end
                    i -> list1.get(i).getValue(),
                    // merge duplicates, if any
                    (s1, s2) -> s1 + "," + s2,
                    // reversed comparator to the one that was before
                    () -> new TreeMap<>(map1.comparator().reversed())));
    
    // output
    map2.forEach((k, v) -> System.out.println(k + " : " + v));
    //4 : First option
    //3 : Second option
    //2 : Third option
    //1 : Last option
    

  2. LinkedHashMap

    LinkedHashMap<String, String> map3 =
            new LinkedHashMap<>() {{
                put("one", "First option");
                put("two", "Second option");
                put("three", "Third option");
                put("four", "Last option");
            }};
    
    List<Map.Entry<String, String>> list2 = new ArrayList<>(map3.entrySet());
    
    LinkedHashMap<String, String> map4 = IntStream.range(0, list2.size())
            .boxed().collect(Collectors.toMap(
                    // from the end to the beginning
                    i -> list2.get(list2.size() - i - 1).getKey(),
                    // from the beginning to the end
                    i -> list2.get(i).getValue(),
                    // merge duplicates, if any
                    (s1, s2) -> s1 + "," + s2,
                    LinkedHashMap::new));
    
    // output
    map4.forEach((k, v) -> System.out.println(k + " : " + v));
    //four : First option
    //three : Second option
    //two : Third option
    //one : Last option
    

See also: How do I sort two arrays in relation to each other?