【问题标题】:Is there any simple way to preserve original indices after sorting array without using Comparator?有没有简单的方法在不使用比较器的情况下对数组进行排序后保留原始索引?
【发布时间】:2021-09-20 01:52:37
【问题描述】:

我实现了一个数组,其中我采用了一个零索引数组。 考虑下面的数组:

Array :             X S T U A C D B F H 
Index :             0 1 2 3 4 5 6 7 8 9
After sorting this array : 
Array :             A B C D F H S T U X
Index :             0 1 2 3 4 5 6 7 8 9
Original indices :  4 7 5 6 8 9 1 2 3 0

之前的 A 位于索引 4 处,但在排序后的数组中,它位于索引 0 处,其他值也相同。 程序的预期输出表示为原始索引。我不想打印排序数组中的元素,而是想在排序后打印它们的原始索引。

虽然这段代码工作正常,但我想知道是否有任何其他简单的技术可以在不使用 Comparator 的情况下保留原始数组索引。这里的想法是保留索引,因此我使用的是 Comparator :

在这个比较器中,我保留了要排序的实际数组。此外,如果您注意到, compare 方法会根据提供给它的索引来比较实际数组的值。这里的关键是提供索引而不是要排序的实际值。

S 是要排序的字符数组,indexArray 是辅助数组。在排序之前,索引数组将包含序列中的数字 0 - 要排序的数组的长度。当我在索引数组上调用 Arrays.sort 方法时,它会将两个索引传递给 compare 方法并比较存储在这些索引处的值。

 ```public class ArrayIndexComparator implements Comparator<Integer>
    {
        private final Character[] A;
        public ArrayIndexComparator(Character[] arr)
        {
            this.A = arr;
        }

        
        public int compare(Integer o1, Integer o2)
        {
            return A[o1].compareTo(A[o2]);
        }
    }```
 ```public static void main(String[] args)
    {
        Character[] S = new Character[]{'X','S','T','U','A','C','D','B','F','H'};
        Integer[] indexArray = new Integer[S.length];
        IntStream.range(0, S.length).forEach(val -> indexArray[val] = val);
        ArrayIndexComparator comp = new ArrayIndexComparator(S);
        Arrays.sort(indexArray, comp);
        System.out.println(Arrays.toString(indexArray));
    }```

【问题讨论】:

  • 注意 java 命名约定。变量名应以小写字符开头
  • 您为什么要这样做?您的比较器方法是一种非常合理的方法,它具有清晰和自我记录的区别。

标签: java arrays performance sorting java-8


【解决方案1】:

你可以这样做。

String[] arr =
        { "X", "S", "T", "U", "A", "C", "D", "B", "F", "H" };

根据字符串对索引进行排序

int[] intArray = IntStream.range(0, arr.length).boxed()
        .sorted(Comparator.comparing(i -> arr[i]))
        .mapToInt(Integer::intValue).toArray();
System.out.println(Arrays.toString(intArray));

然后使用Arrays.setAll构造排序后的字符数组。

String[] newArr = new String[arr.length];
Arrays.setAll(newArr,i->arr[intArray[i]]);
System.out.println(Arrays.toString(newArr));

打印

[4, 7, 5, 6, 8, 9, 1, 2, 3, 0]
[A, B, C, D, F, H, S, T, U, X]

【讨论】:

    【解决方案2】:

    至少有几种方法可以避免使用自定义 Comparator 按索引而不是值进行排序,但它们并不简单,我强烈建议不要使用它们 - 我在这里提出了主题为了利益。

    顺便说一句,使用 Comparator 的 lambda 形式可以稍微简化您的代码:

    Arrays.setAll(indexArray, i -> i);    
    Arrays.sort(indexArray, (a, b) -> S[a].compareTo(S[b]));
    

    第一个想法是创建一个结合原始Character 值及其索引的代理值,例如通过将值乘以数组n 的长度并添加索引。在对该代理值进行排序后,您可以通过使用 mod n 来获取索引来反转包装。

    Character[] s = new Character[]{'X','S','T','U','A','C','D','B','F','H'};
    
    int n = s.length;
    
    Integer[] idx = new Integer[s.length];
    for(int i=0; i<s.length; i++) idx[i] = s[i]*n + i;
    
    System.out.println(Arrays.toString(idx));
    
    Arrays.sort(idx);
    
    System.out.println(Arrays.toString(idx));
    
    for(int i=0; i<s.length; i++) idx[i] %= n;
    
    System.out.println(Arrays.toString(idx));
    

    输出:

    [880, 831, 842, 853, 654, 675, 686, 667, 708, 729]
    [654, 667, 675, 686, 708, 729, 831, 842, 853, 880]
    [4, 7, 5, 6, 8, 9, 1, 2, 3, 0]
    

    这里明显的问题是在大数组和/或字符的情况下溢出。

    另一种选择是使用地图来存储字符的原始位置,并在对原始数组进行排序后执行查找。

    Character[] s = new Character[]{'X','S','T','U','A','C','D','B','F','H'};
    
    Map<Character,Integer> map = new HashMap<>();
    for(int i=0; i<s.length; i++) map.put(s[i], i);
    
    System.out.println(map);
    
    Arrays.sort(s);
    
    Integer[] idx = new Integer[s.length];
    for(int i=0; i<s.length; i++) idx[i] = map.get(s[i]);
    
    System.out.println(Arrays.toString(idx));
    

    输出:

    {A=4, B=7, C=5, S=1, D=6, T=2, U=3, F=8, H=9, X=0}
    [4, 7, 5, 6, 8, 9, 1, 2, 3, 0]
    

    这里的问题是不允许重复。

    【讨论】:

    • 所以我猜我只能使用 Comparator。
    【解决方案3】:

    您可以使用Comparator.comparing 更轻松地定义您的比较器。

    Comparator<Integer> comp = Comparator.comparing(i -> S[i]);
    

    【讨论】:

      猜你喜欢
      • 2014-08-13
      • 2017-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      • 2016-12-25
      • 2022-11-15
      相关资源
      最近更新 更多