Java: 使用 indexOf 方法基于另一个数组对数组进行排序

Java: Sorting an array based on another array with indexOf method

我想根据另一个数组(索引)的排序顺序遍历两个数组(A、B),在本例中为 10、34、32、21。

String[] A: a, b, c, d
String[] B: e, f, g, h
int[] indexes: 10, 34, 32, 21

Apology for the bad example here. I have updated the indexes array to clear the confusion.

预期输入和输出

输入是三个数组。我想使用索引数组的排序来遍历 A、B。即我想找到一种使用顺序 (a, d, c, b) 迭代 A 并使用顺序 (e, h, g, f)

迭代 B 的方法

我的做法:

我用我认为与另一种方法相同的解决方案解决了这个问题。然而,第二种方法 工作。如果有人能解释为什么它不起作用,我将不胜感激,因为我认为这会让我更好地理解 Collections.sort 在 java 中的工作原理。

List<Integer> indexOrder = new ArrayList<>(indexes.length);

for (int i = 0; i < indexes.length; i++) {
    indexOrder.add(i);
}

Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[s]));

this thread 的启发,我创建了一个值为 (1, 2, 3...indexes.length) 的 ArrayList(更喜欢 AList 而不是数组),然后使用带有 ref 的比较器对其进行排序。到索引。 以上代码按预期工作。

但是,如果我将最后一行末尾的 indexes[s] 更改为 indexes[indexOrder.indexOf(s)]。排序会给出错误的结果。如果 ArrayList 的索引与其值相同,为什么 indexOf(s) 给出的结果与 s 不同。

Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[indexOrder.indexOf(s)]));

您似乎希望 indexOrder.indexOf(s) 始终等于 s(因为您的 List 已初始化为 [0, 1, 2, 3],其中 s 的索引是 s)。

虽然这在您的原始 indexOrder List 中是正确的,但当 Collections.sort 开始交换您的 List.

的元素时,这可能不再正确

为了在排序时不依赖 indexOrder 的顺序,您可以创建 List 的副本:

List<Integer> copy = new ArrayList<>(indexOrder);
Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[copy.indexOf(s)]));

由于存储在索引中的最大值不会超过 1000,我觉得实现这种排序算法(它是计数排序的一种变体)将是最佳选择。

final String[] A = { "a", "b", "c", "d" };
final String[] B = { "e", "f", "g", "h" };
final int[] indexes =  { 10, 34, 32, 21 };

// find out the max value in the array.
// The loop can be skipped with maxIndexValue = 1000; but i would most likely save some memory using the loop.
// Can also be replaced with : IntStream.of(indexes).max().getAsInt(), with such a small set of data it won't hurt performance that bad
int maxIndexValue = 0;
for (int indexValue: indexes) {
    if (maxIndexValue < indexValue) {
        maxIndexValue = indexValue;
    }
}
maxIndexValue += 1;

final String[] indexSortedA = new String[maxIndexValue];
final String[] indexSortedB = new String[maxIndexValue];
System.out.println(maxIndexValue);
// each value of A (and B) will be put at indexes position, it will result in a appropriately sorted arrays but with a lot of whitespace.
for (int i = 0; i < indexes.length; ++i) {
    indexSortedA[indexes[i]] = A[i];
    indexSortedB[indexes[i]] = B[i];
}

// Create final arrays by filtering empty values
final String[] sortedA = Arrays.stream(indexSortedA).filter(v -> v != null && !"".equals(v)).toArray(String[]::new);
final String[] sortedB = Arrays.stream(indexSortedB).filter(v -> v != null && !"".equals(v)).toArray(String[]::new);

该算法的复杂度为:O(n) + O(1000) + O(2n)。它会比任何一个更好 Collection.sort() 但它会花费更多的内存。

我尝试 运行 这两种代码,在两种情况下我都得到了相同的结果。

案例 1:

public static void main(String[] args) {
    String[] A = { "a", "b", "c", "d" };
    String[] B = { "e", "f", "g", "h" };
    int[] indexes = { 0, 4, 2, 1 };

    List<Integer> indexOrder = new ArrayList<>(indexes.length);

    for (int i = 0; i < indexes.length; i++) {
        indexOrder.add(i);
        System.out.println(i);
    }

    //Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[s]));
    Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[indexOrder.indexOf(s)]));

    System.out.println(indexOrder.toString());
}

输出: 0 1个 2个 3

[0, 3, 2, 1]

案例 2:

public static void main(String[] args) {
    String[] A = { "a", "b", "c", "d" };
    String[] B = { "e", "f", "g", "h" };
    int[] indexes = { 0, 4, 2, 1 };

    List<Integer> indexOrder = new ArrayList<>(indexes.length);

    for (int i = 0; i < indexes.length; i++) {
        indexOrder.add(i);
        System.out.println(i);
    }

    Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[s]));
    //Collections.sort(indexOrder, Comparator.comparing((Integer s) -> indexes[indexOrder.indexOf(s)]));

    System.out.println(indexOrder.toString());
}

输出: 0 1个 2个 3

[0, 3, 2, 1]