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?

auntyellow
  • 2,423
  • 2
  • 20
  • 47
  • 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. – Obicere Dec 29 '17 at 07:54

3 Answers3

12

Since java-9 this could be greatly simplified with :

 TreeMap<int[], String> map = new TreeMap<>(Arrays::compare);
Eugene
  • 117,005
  • 15
  • 201
  • 306
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;
    });
Riaan Nel
  • 2,425
  • 11
  • 18
  • 2
    Be sure to check the lengths first. Only enter the loop if the lengths are equal. Otherwise, +1. – Obicere Dec 29 '17 at 07:58
  • Good point - I noticed that as I posted it. I updated the original answer to indicate the assumption. – Riaan Nel Dec 29 '17 at 07:59
  • 3
    @Obicere 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). – talex Dec 29 '17 at 08:06
  • 1
    @talex exactly. I'd personally do it the same way. Just `Integer.compareTo(o1.length, o2.length)`. – Obicere Dec 29 '17 at 08:07
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;
Lino
  • 19,604
  • 6
  • 47
  • 65