Java - 根据另一个数组的值对一个数组进行排序?

Rez*_*eza 3 java sorting algorithm

我有一个字符串数组,它是来自外部代码的类的实例,我宁愿不改变.

我还有一个通过调用每个对象上的函数生成的一组int.所以我有

A: [string1, string2, string3]

B: [40, 32, 34]

如何轻松地对A进行排序,使其按B的值排序.我有可用的提升.我想按顺序排序A:

[string2, string3, string1]
Run Code Online (Sandbox Code Playgroud)

在javascript中你可以这样做:

B.sort(function(a,b){return A[B.indexOf(a)] < A[B.indexOf(b)];});
Run Code Online (Sandbox Code Playgroud)

The*_*ech 9

在java 8中,您可以这样做

与lambda:

    String[] strings = new String[]{"string1", "string2", "string3"};
    final int[] ints = new int[]{40, 32, 34};

    final List<String> stringListCopy = Arrays.asList(strings);
    ArrayList<String> sortedList = new ArrayList(stringListCopy);
    Collections.sort(sortedList, (left, right) -> ints[stringListCopy.indexOf(left)] - ints[stringListCopy.indexOf(right)]);
Run Code Online (Sandbox Code Playgroud)

或者更好,与比较器:

    String[] strings = new String[]{"string1", "string2", "string3"};
    final int[] ints = new int[]{40, 32, 34};

    final List<String> stringListCopy = Arrays.asList(strings);
    ArrayList<String> sortedList = new ArrayList(stringListCopy);
    Collections.sort(sortedList, Comparator.comparing(s -> ints[stringListCopy.indexOf(s)]));
Run Code Online (Sandbox Code Playgroud)

  • 该算法在性能方面效率不高,因为每个 indexOf(s) 都以线性时间运行来查找索引。所以最坏情况的性能是 O(n*n*logn),而不是 O(n*logn) (4认同)

Ofe*_*fek 8

正如@wassgren所说,您可以使用流,但不必创建类,您可以只使用索引:

String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};

String[] sorted = IntStream.range(0, boosts.length).boxed()
        .sorted(Comparator.comparingInt(i -> boosts[i]))
        .map(i -> strings[i])
        .toArray(String[]::new);
Run Code Online (Sandbox Code Playgroud)

首先,您创建一个索引流,然后根据提升对它们进行排序,然后获取该索引中的字符串。

  • 这是迄今为止最好的答案。保持 O(nlogn) 性能,避免“indexOf”解决方案都存在的重复问题,并避免创建数据并将其复制到辅助对象中。 (2认同)

was*_*ren 5

简短的回答:我建议创建一个单独的类来保存有关实际String和增强(the int)的信息.如果您假设以下内容:

public class BoostString {
    int boost;
    String str;

    public BoostString(int boost, String str) {
        this.boost = boost;
        this.str = str;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用a对数组进行排序Comparator,它对Java 8 Streaming API特别有用.

String[] strings = {"string1", "string2", "string3"};
int[] boosts = {40, 32, 34};

final String[] sorted = IntStream.range(0, boosts.length)
        .mapToObj(i -> new BoostString(boosts[i], strings[i])) // Create the instance
        .sorted(Comparator.comparingInt(b -> b.boost))         // Sort using a Comparator
        .map(b -> b.str)                                       // Map it back to a string
        .toArray(String[]::new);                               // And return an array
Run Code Online (Sandbox Code Playgroud)

Comparator以上示例中,使用所创建的Comparator.comparingInt这是一个创建的便利方式的方法Comparator使用Java 8整数.


说明:通常在比较Java中的对象时,您可以使用其中一个内置排序函数,例如Collections.sort您提供自己的排序函数Comparator.该Comparator接口非常简单,看起来像这样:

public interface Comparator<T> {
    int compare(T o1, T o2);

    // Other default methods for Java 8
}
Run Code Online (Sandbox Code Playgroud)

返回值是类型int,在JavaDoc中如下所述:

返回负整数,零或正整数,因为第一个参数小于,等于或大于第二个参数.

当你排序Strings或int(或实际上是Integers)时,这是开箱即用的,因为它们是Comparable- 它们有一种内置的自然排序,而且String这是按字母顺序排列的,并且Integers按升序排序顺序(见的JavaDocComparable).

另外,如果您使用的是第三方库,还有其他"对"或"元组"实现可用.您不必创建自己的"对" Stringint.一个例子是来自Apache CommonsPair类.


The*_*111 -2

创建一个TreeMap<Integer, List<ObjectTypeFromA>>,其中映射键是 B 中的值,映射值是 A 中的值(使用列表以允许重复键)。根据定义,它将按照 B 的顺序排序。

public static void main(String[] args) {
  String[] strings = { "string1", "string2", "string3", "string4" };
  int[] ints = { 40, 32, 32, 34 };
  System.out.println(Arrays.toString(getSortedStringArray(strings, ints)));
}

public static String[] getSortedStringArray(String[] strings, int[] order) {
  Map<Integer, List<String>> map = new TreeMap<>();
  for (int i = 0; i < strings.length; i++) {
    if (!map.containsKey(order[i])) {
      map.put(order[i], new LinkedList<String>());
    }
    map.get(order[i]).add(strings[i]);
  }
  String[] ret = new String[strings.length];
  int i = 0;
  for (Map.Entry<Integer, List<String>> mapEntry : map.entrySet()) {
    for (String s : mapEntry.getValue()) {
      ret[i++] = s;
    }
  }
  return ret;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果 B 有重复项怎么办? (2认同)