简体   繁体   中英

How to sort a Map by Key and Value, whereas the Val is a Map/List itself

I am having a hard time understanding the right syntax to sort Maps which values aren't simply one type, but can be nested again. I'll try to come up with a fitting example here:

Let's make a random class for that first:

class NestedFoo{
int valA;
int valB;
String textA;

public NestedFoo(int a, int b, String t){
  this.valA = a;
  this.valB = b;
  this.textA = t;
  }
}

Alright, that is our class. Here comes the list:

HashMap<Integer, ArrayList<NestedFoo>> sortmePlz = new HashMap<>();

Let's create 3 entries to start with, that should show sorting works already.

ArrayList<NestedFoo> l1 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,2,"a");
n3 = new NestedFoo(1,4,"c");
l1.add(n1);
l1.add(n2);
l1.add(n3);

ArrayList<NestedFoo> l2 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,2,"a");
n3 = new NestedFoo(2,2,"b");
n4 = new NestedFoo(1,4,"c");
l2.add(n1);
l2.add(n2);
l2.add(n3);
l2.add(n4);

ArrayList<NestedFoo> l3 = new ArrayList<>();
n1 = new NestedFoo(3,2,"a");
n2 = new NestedFoo(2,3,"b");
n3 = new NestedFoo(2,2,"b");
n4 = new NestedFoo(5,4,"c");
l3.add(n1);
l3.add(n2);
l3.add(n3);
l3.add(n4);

Sweet, now put them in our Map.

sortmePlz.put(5,l1);
sortmePlz.put(2,l2);
sortmePlz.put(1,l3);

What I want now, is to sort the Entire Map first by its Keys, so the order should be l3 l2 l1. Then, I want the lists inside each key to be sorted by the following Order: intA,intB,text (all ascending)

I have no idea how to do this. Especially not since Java 8 with all those lambdas, I tried to read on the subject but feel overwhelmed by the code there.

Thanks in advance! I hope the code has no syntatical errors, I made it up on the go

You can use TreeSet instead of regular HashMap and your values will be automatically sorted by key :

Map<Integer, ArrayList<NestedFoo>> sortmePlz = new TreeMap<>();

Second step I'm a little confused.

to be sorted by the following Order: intA,intB,text (all ascending)

I suppose you want to sort the list by comparing first the intA values, then if they are equal compare by intB and so on. If I understand you correctly you can use Comparator with comparing and thenComparing .

sortmePlz.values().forEach(list -> list
            .sort(Comparator.comparing(NestedFoo::getValA)
                            .thenComparing(NestedFoo::getValB)
                            .thenComparing(NestedFoo::getTextA)));

I'm sure there are way of doing it with lambda but it is not actually required . See answer from Schidu Luca for a lambda like solution.

Keep reading if you want an 'old school solution'.

You cannot sort a map. It does not make sense because there is no notion of order in a map. Now, there are some map objects that store the key in a sorted way (like the TreeMap ).

You can order a list. In your case, makes the class NestedFoo comparable ( https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html ). Then you can invoke the method Collections.sort ( https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#sort-java.util.List- ) on your lists.

Use TreeMap instead of HashMap, it solves the 1st problem: ordering entries by key.

After getting the needed list from the Map, you can sort the ArrayList by valA, valB, text:

l1.sort(
                Comparator.comparing(NestedFoo::getValA).thenComparing(NestedFoo::getValB).thenComparing(NestedFoo::getTextA)
        );

And change your NestedFoo class definition like this:

class NestedFoo {
        int valA;
        int valB;
        String textA;

        public NestedFoo(int a, int b, String t) {
            this.valA = a;
            this.valB = b;
            this.textA = t;
        }

        public int getValA() {
            return valA;
        }

        public void setValA(int valA) {
            this.valA = valA;
        }

        public int getValB() {
            return valB;
        }

        public void setValB(int valB) {
            this.valB = valB;
        }

        public String getTextA() {
            return textA;
        }

        public void setTextA(String textA) {
            this.textA = textA;
        }
    }

When using treemap for sorting keep in mind that treemap uses compareTo instead of equals for sorting and to find duplicity. compareTo should be incosistent with equals and hashcode when implemented for any object which will be used as key. You can look for a detailed example on this link https://codingninjaonline.com/2017/09/29/unexpected-results-for-treemap-with-inconsistent-compareto-and-equals/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM