gaout5
gaout5

Reputation: 69

Sorting Entries in Map by Size of Lists

I have a Map consisting of a String and a corresponding List. The lists have different sizes:

Map<String, List<String>> map = new LinkedHashMap<>();

List<String> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
List<String> l3 = new ArrayList<>();

l1.add("Str1");
l1.add("Str2");
l2.add("Str1");
l2.add("Str2");
l2.add("Str3");
l3.add("Str1");

map.put("Category A", l1);
map.put("Category B", l2);
map.put("Category C", l3);

I want to sort the entries of the Map by the size of the Lists, in descending order. So in my example the final result should be:

Category B: Str1, Str2, Str3
Category A: Str1, Str2
Category C: Str1

I tried:

for (Map.Entry<String, List<String>> entry : map.entrySet()) {
    entry.getValue().sort(new Comparator<String>() {
        public int compare(ArrayList a1, ArrayList a2) {
            return a2.size() - a1.size();
        }
});

But I get:

java: <anonymous com.app.class> is not abstract and does not override abstract method compare(java.lang.String,java.lang.String) in java.util.Comparator

Upvotes: 2

Views: 665

Answers (2)

Giorgi Tsiklauri
Giorgi Tsiklauri

Reputation: 11120

You can introduce another instance of Map<K, V> (such that preserves an insertion order, e.g. LinkedHashMap<K, V>), and insert the entries in it, in the order mandated by your comparator:

Map<String, List<String>> map = new LinkedHashMap<>();

List<String> l1 = new ArrayList<>();
List<String> l2 = new ArrayList<>();
List<String> l3 = new ArrayList<>();

l1.add("Str1");
l1.add("Str2");
l2.add("Str1");
l2.add("Str2");
l2.add("Str3");
l3.add("Str1");

map.put("Category A", l1);
map.put("Category B", l2);
map.put("Category C", l3);


LinkedHashMap<String, List<String>> descByValues = new LinkedHashMap<>();

map.entrySet()
        .stream()
        .sorted((e1, e2) -> e2.getValue().size() - e1.getValue().size())
        .forEachOrdered(x -> descByValues.put(x.getKey(), x.getValue()));

and then:

descByValues
        .forEach((k, v) -> System.out.println(k + ", " + v));

will output:

Category B, [Str1, Str2, Str3]
Category A, [Str1, Str2]
Category C, [Str1]

Upvotes: 4

NoDataFound
NoDataFound

Reputation: 11959

This won't do what you are trying to do:

for (Map.Entry<String, List<String>> entry : map.entrySet()) {
    entry.getValue().sort(new Comparator<String>() {
        public int compare(ArrayList a1, ArrayList a2) {
            return a2.size() - a1.size();
        }
});

Your error is due to the type:

Map.Entry<String, List<String>> entry

This means that entry.getValue() returns a List<String> and also that List.sort(Comparator<T>) works only with a Comparator<String> because T = String.

If you want to sort by the size of List, you will have to lose the category:

List<List<String>> list = new ArrayList<>(map.values());
list.sort((a1, a2) -> a2.size() - a1.size());

If you need to keep up the category, then you would need an intermediate type to keep the mapping:

List<Map.Entry<String, List<String>>> list = new ArrayList<>(map.entrySet());
list.sort((a1, a2) -> a2.getValue().size() - a1.getValue()..size());

Do note that I used a List rather than modifying the Map: not all map allows sorting, and those that allows sorting (SortedMap) mostly sort on the keys.

Upvotes: 1

Related Questions