2

Disclaimer : I have already once posted such a question and it was marked duplicate. Please try and help me. I have gone through all previous methods on stackoverflow and none was of any help. All the methods mentioned to sort Map(Key,Values) didn't work in my case as I have one step further i.e. retrieving the attribute of the value. This time, I tried to go with full detail.

I've a Map (String,Object) in Java and I want to sort it using one of the attributes of the Object.

e.g. Suppose I have a class

class Entry
{
    int id;
    String name;
    String address;
    //Rest of the code
}

Now, I created a map

 Map<String,Entry>

I want to sort the map by the attribute id of the class Entry (Entry.id)

Please help !

For example, I have three objects of Entry class

entry1 :
        id=1
        name="abc"
        address="india"
entry2 :
        id=2
        name="xyz"
        address="india"
entry3 :
        id=3
        name="pqr"
        address="india"

Now, I have the Map initially as follows :

Key :   Value
first:  entry2
second: entry3
third : entry1

After sorting, it should be like

Key :   Value
third : entry1
first:  entry2
second: entry3
  • 2
    Possible duplicate of [Create a SortedMap in Java with a custom Comparator](https://stackoverflow.com/questions/2748829/create-a-sortedmap-in-java-with-a-custom-comparator) – M. le Rutte May 21 '18 at 16:48
  • 4
    It is impossible to sort `Map` by values or attributes of values in Java out of the box. Depending on what you really need to do with that sorted `Map` you might need to have a separate data structure for sorted objects – Ivan May 21 '18 at 16:50
  • Why do you want the map (entries) sorted? – Bohemian May 21 '18 at 16:57

3 Answers3

6

You can easily accomplish the task with the stream API:

Map<String, Entry> resultSet = myMap.entrySet()
                .stream()
                .sorted(Comparator.comparingInt(e -> e.getValue().getId()))
                .collect(Collectors.toMap(Map.Entry::getKey,
                        Map.Entry::getValue,
                        (left, right) -> left,
                        LinkedHashMap::new));
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • 3
    “easy” is obviously subjective. This doesn’t look easy to me. – Bohemian May 21 '18 at 16:56
  • @Bohemian what difficulty are you having to to understand the code? – Ousmane D. May 21 '18 at 16:59
  • IMHO it’s what I call a “train wreck”. You can **not** understand what your code is doing at a glance. That fact makes it rank lower on the “goodness” scale. Compare your code with [this](https://stackoverflow.com/a/50453540/256196) (which I *think* works). – Bohemian May 21 '18 at 17:09
  • @Bohemian "IMHO" is obviously subjective as well. – Ousmane D. May 21 '18 at 17:11
  • @Bohemian Further, when you say "You can not understand what your code is doing at a glance." I don't see anything difficult to understand here, this is as simple as it gets when all you want to do is sort the map. – Ousmane D. May 21 '18 at 17:19
1

Your requirement is typically a symptom of bad data-structure usage.

If you wanted the map to be sorted by an attribute of key objects, you would just write a custom comparator, but since you want to sort by values, it's a bit more complicated.

Try understanding answers to this question: Sort a Map<Key, Value> by values. And then try using a custom comparator in combination.

Amila
  • 5,195
  • 1
  • 27
  • 46
-3

You can’t sort a map.

You can have a map that keeps its entries sorted, or you can sort a List<Map.Entry>.

Try this:

Map<String, Entry> map; // your map
Map<String, Entry> sorted = new TreeMap<>(Comparator.comparing(s -> map.get(s).getId());
sorted.putAll(map);
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    more efficient to use `Comparator.comparingInt` as opposed to `Comparator.comparing` – Ousmane D. May 21 '18 at 17:11
  • @Aominè more efficient? It’s more code and I doubt you could measure the difference in timing. – Bohemian May 21 '18 at 21:34
  • Seriously... more code by _only_ 3 letters. Yes you could measure the difference and why go for a suboptimal solution when you can go to the most optimal solution by only adding 3 letters. It’s a no brainer really, I’d jump at having the most optimal code all the time. – Ousmane D. May 21 '18 at 21:38
  • @Aominè let’s get something straight: in virtually all applications (all except super low latency requirements like ticker processing, where they don’t even run a garbage collector), you could not measure the difference in performance - it would be single digit nanoseconds for what is more or less a one-time operation. There are other factors too: by coding `comparingInt()`, you’re locking in `int` as the type for `id`. If that changed to a String or guid, you’d have to come back here and change this code too. Using `comparing()` is more flexible, it works with all types - that’s good practice – Bohemian May 21 '18 at 23:14
  • 1
    I have the feeling the more I reply to your comments we’ll be here for eternity so let’s call it a day. – Ousmane D. May 22 '18 at 07:42