-2

As an input, I have List of objects, each object has name and map:

1)
  Name: m1

  Map: {"c1": 3,
 "c2": 24
 "c3": 12}

2) Name: m2

Map: {"c1": "A",
 "c2": "B",
 "c3": "C"}

3) Name: m3

Map: {"c1": 3.4,
 "c2": 4.6,
 "c3": 12.3}

What I need as an output, I need to sort all 3 maps based on values in map with name m1.

So first, I want to sort map for object#1(m1) by values in descending orders (I can use LinedHashMap here):

{"c1": 3, "c2": 24, "c3": 12}  =>  {"c2": 24, "c3": 12, "c1": 3} 

And now, I want elements in map for object#2 and map for object#3, also be sorted in the same key orders - C2, C3, C1. So basically I want reorder 2 maps so that order is C2, C3, C1 (the same order as in m1), and NOT C1, C2, C3.

How can I do it most elegant way? I have some solutions - but they are messy, and have a lot of extra steps.

If it's matter: this list will always have only 3 objects. Number of elements in Map can be different, but keys in maps will always be the same across 3 maps

Ousmane D.
  • 50,173
  • 8
  • 66
  • 103
Bilberryfm
  • 387
  • 6
  • 18

1 Answers1

1

So you know how to sort a Map by value, maybe by reading this answer: Sort a Map by values (Java), where the Java 8 version of the answer is:

m1sorted = m1.entrySet()
             .stream()
             .sorted(Map.Entry.comparingByValue(Collections.reverseOrder()))
             .collect(Collectors.toMap(
               Map.Entry::getKey,
               Map.Entry::getValue,
               (e1, e2) -> e1,
               LinkedHashMap::new
             ));

So how do you sort m2 and m3 by the values of m1?

Easy: You supply a Comparator to sorted() that compares the values, e.g.

.sorted(Comparator.comparing(e -> m1.get(e.getKey())).reversed())

You may have to explicitly specify the type of e, since the inference engine may get lost: comparing((Entry<String, String> e) ->

If you don't like Comparator.comparing() and reversed(), and the inference issue, you can just use a lambda.

Here is all the code, as proof of concept:

Map<String, Integer> m1 = new HashMap<>();
m1.put("c1", 3);
m1.put("c2", 24);
m1.put("c3", 12);

Map<String, String> m2 = new HashMap<>();
m2.put("c1", "A");
m2.put("c2", "B");
m2.put("c3", "C");

Map<String, Double> m3 = new HashMap<>();
m3.put("c1", 3.4);
m3.put("c2", 4.6);
m3.put("c3", 12.3);
Map<String, Integer> m1s =
        m1.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue()))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));

Map<String, String> m2s =
        m2.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey())))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));

Map<String, Double> m3s =
        m3.entrySet()
          .stream()
          .sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey())))
          .collect(Collectors.toMap(Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (e1, e2) -> e1,
                                    LinkedHashMap::new));
System.out.println(m1s);
System.out.println(m2s);
System.out.println(m3s);

Output

{c2=24, c3=12, c1=3}
{c2=B, c3=C, c1=A}
{c2=4.6, c3=12.3, c1=3.4}

Notice how e2 and e1 are reversed in the lambdas to cause descending order.

Of course, it would be much better to use the Object-Oriented features of Java and only have one Map to objects with three fields for the values.

Andreas
  • 138,167
  • 8
  • 112
  • 195
  • This is all very well but it doesn't actually sort the Map. – user207421 Dec 21 '17 at 00:15
  • 1
    @EJP It actually does sort the Map. Of course, you have to redo the sort any time you add/update a value, but this is the closest you can get to a Map sorted by value. Never said it was efficient, but it is what it is ... – Andreas Dec 21 '17 at 06:07
  • @Andreas Thanks for helping. I like your approach, but I think that this line is doing not exactly what I expected in m2s and m3s: **.sorted((e1, e2) -> Integer.compare(m1.get(e2.getKey()), m1.get(e1.getKey())))** It seems like it sorted m2s and m3s maps based on VALUES of m1s map, and not KEYS. I need it to sorted by keys of m1s map. How to create such comparator? – Bilberryfm Dec 21 '17 at 19:07
  • @Bilberryfm You said *"I need to sort all 3 maps based on **values in** map with name **m1**"*. That's what this code does: See "*Output*". Values of `m1` in descending order is `24, 12, 3`, so keys must be in order `c2, c3, c1` in **all 3 maps**. – Andreas Dec 21 '17 at 21:45