How to make TreeMap work with Arrays as key?
Asked Answered
P

3

6

Similar question see: How to make HashMap work with Arrays as key?

But I need TreeMap like ((int key1, int key2) -> String), comparing key1 then comparing key2.

My solution is:

    Map<int[], String> map = new TreeMap<>(Comparator.
            <int[]>comparingInt(key -> key[0]).thenComparingInt(key -> key[1]));

But when I need ((int key1, int key2, int key3) -> String, I must write more.

Is there a way to generate the Comparator for arrays with arbitrary length?

Potluck answered 29/12, 2017 at 7:47 Comment(1)
Probably the best way would be to just write a Comparator that does exactly that. I doubt that could be reasonably and understandably done with lambdas. If you can do it with a lambda, go for it, but personally I'd just use regular Java.Lagunas
L
6

A Comparator with a loop should do the trick. Something like this, if I understood your requirement correctly. I should mention that it assumes that all keys are of the same length.

    Map<int[], String> treeMap = new TreeMap<>((o1, o2) -> {
        for (int i = 0; i < o1.length; i++) {
            if (o1[i] > o2[i]) {
                return 1;
            } else if (o1[i] < o2[i]) {
                return -1;
            }
        }

        return 0;
    });
Lazy answered 29/12, 2017 at 7:58 Comment(4)
Be sure to check the lengths first. Only enter the loop if the lengths are equal. Otherwise, +1.Lagunas
Good point - I noticed that as I posted it. I updated the original answer to indicate the assumption.Lazy
@Lagunas if you do this you break symmetry requirement. You should return +1 in case first array is longer and -1 otherwise (or opposite, depending of what you want).Riffraff
@talex exactly. I'd personally do it the same way. Just Integer.compareTo(o1.length, o2.length).Lagunas
C
12

Since java-9 this could be greatly simplified with :

 TreeMap<int[], String> map = new TreeMap<>(Arrays::compare);
Cavernous answered 29/12, 2017 at 8:24 Comment(0)
L
6

A Comparator with a loop should do the trick. Something like this, if I understood your requirement correctly. I should mention that it assumes that all keys are of the same length.

    Map<int[], String> treeMap = new TreeMap<>((o1, o2) -> {
        for (int i = 0; i < o1.length; i++) {
            if (o1[i] > o2[i]) {
                return 1;
            } else if (o1[i] < o2[i]) {
                return -1;
            }
        }

        return 0;
    });
Lazy answered 29/12, 2017 at 7:58 Comment(4)
Be sure to check the lengths first. Only enter the loop if the lengths are equal. Otherwise, +1.Lagunas
Good point - I noticed that as I posted it. I updated the original answer to indicate the assumption.Lazy
@Lagunas if you do this you break symmetry requirement. You should return +1 in case first array is longer and -1 otherwise (or opposite, depending of what you want).Riffraff
@talex exactly. I'd personally do it the same way. Just Integer.compareTo(o1.length, o2.length).Lagunas
D
1

You could make a factory method, which creates a comparator comparing the lengths of the arrays and their values:

public static Comparator<int[]> intArrayComparator(){
    return ( left, right ) -> {
        int comparedLength = Integer.compare(left.length, right.length);
        if(comparedLength == 0){
            for( int i = 0; i < left.length; i++ ){
                int comparedValue = Integer.compare(left[i], right[i]);
                if(comparedValue != 0){
                    return comparedValue;
                }
            }
            return 0;
        } else {
            return comparedLength;
        }
    };
}

Which you could call like the following then:

Map<int[], String> treeMap = new TreeMap<>(intArrayComparator());

Above comparator has following cases:

  • Left is bigger than right: return 1
  • Left is smaller than right: return -1
  • Item at index i in left array is bigger than the one from the right array: return 1
  • Item at index i in left array is smaller than the one from the right array: return -1
  • Left is deep equal to right: return 0;
Dogoodism answered 29/12, 2017 at 8:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.