如何使TreeMap与数组作为键一起工作?

6

类似的问题请参见:如何使HashMap与数组作为键一起工作?

但我需要像((int key1,int key2) -> String)这样的TreeMap,先比较key1,然后再比较key2

我的解决方案是:

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

但是当我需要 ((int key1, int key2, int key3) -> String 时,我必须写更多的代码。

有没有一种方法可以为具有任意长度的数组生成比较器呢?


1
可能最好的方法就是编写一个完全实现这一功能的Comparator。我怀疑使用lambda表达式可能无法合理且易于理解地完成这个任务。如果你能用lambda表达式做到,那就去试试吧,但个人而言,我会选择普通的Java方式来实现。 - Obicere
3个回答

12

自 Java 9 起,这个过程可以大大简化:

 TreeMap<int[], String> map = new TreeMap<>(Arrays::compare);

6

使用带有循环的比较器应该能够解决问题。如果我正确理解了您的要求,可以像这样实现。需要注意的是,它假设所有键都具有相同的长度。

    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;
    });

2
请务必先检查长度。只有在长度相等的情况下才进入循环。否则,+1。 - Obicere
好的观点 - 我在发布时注意到了。我更新了原始答案以指示假设。 - Riaan Nel
3
如果你这样做,就会违反对称性要求。如果第一个数组更长,应返回+1,否则应返回-1(或相反,这取决于你的意图)。 - talex
1
@talex 没错。我个人也会这样做。只需 Integer.compareTo(o1.length, o2.length) - Obicere

1
你可以创建一个工厂方法,用于创建比较数组长度和值的比较器:
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;
        }
    };
}

你可以像下面这样调用它:
Map<int[], String> treeMap = new TreeMap<>(intArrayComparator());

以上比较器具有以下情况:

  • 左侧大于右侧:返回1
  • 左侧小于右侧:返回-1
  • 左侧数组中索引为i的项大于右侧数组中的项:返回1
  • 左侧数组中索引为i的项小于右侧数组中的项:返回-1
  • 左侧与右侧完全相等:返回0;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接