【问题标题】:How do I sort a list and use its changed indexes to sort another list in java? [duplicate]java - 如何对列表进行排序并使用其更改的索引对java中的另一个列表进行排序? [复制]
【发布时间】:2021-04-15 00:26:20
【问题描述】:

我有 3 个列表:

ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4)); 
ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));

如果我对at 进行排序,我将得到[0, 2, 2, 3, 4]。
我希望btprc 都遵循这种模式。即:bt =[1, 2, 3, 5, 4]prc=["p2", "p1", "p3", "p4", "p5"]。由于在at 处,索引 1 在排序时与索引 2 交换,我希望其他 2 个数组也发生同样的事情。

我尝试在 Python 中实现它。这很容易,因为如果值在数据框中,对一列进行排序将自动给出所需的结果。我不能在 Java 中做同样的事情。

【问题讨论】:

    标签: java arrays list sorting


    【解决方案1】:

    方法一(先提取索引,再构造新列表)

    如果你可以改变数据格式并使用自定义对象,我推荐使用方法2。

    您可以先将at中原始元素的索引提取到数组sortedIndices中。如果列表已排序,则值为[1, 2, 3, ..., n-1]。如果需要交换前两个元素,则值为[1, 0, 2, 3, ..., n-1]。之后,您可以根据存储的位置sortedIndices[i]添加元素来构造和填充两个排序列表(btSorted/prcSorted)。

    ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
    ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
    ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
    
    // get indexes of a sorted 'at' list
    int[] sortedIndices = IntStream.range(0, at.size())
            .boxed().sorted(Comparator.comparing(at::get))
            .mapToInt(x -> x).toArray();
    
    // sort 'bt' according to 'at'
    ArrayList<Integer> btSorted = new ArrayList<>();
    for (int i = 0; i < sortedIndices.length; i++) {
        btSorted.add(bt.get(sortedIndices[i]));
    }
    
    // sort 'prc' according to 'at'
    ArrayList<String> prcSorted = new ArrayList<>();
    for (int i = 0; i < sortedIndices.length; i++) {
        prcSorted.add(prc.get(sortedIndices[i]));
    }
    
    // sort 'at' directly (just for inspection)
    ArrayList<Integer> atSorted = new ArrayList<>(at);
    Collections.sort(atSorted);
    
    System.out.println("idx: " + Arrays.toString(sortedIndices));
    System.out.println("at:  " + at + " => " + atSorted);
    System.out.println("bt:  " + bt + " => " + btSorted);
    System.out.println("prc: " + prc + " => " + prcSorted);
    

    输出:

    idx: [1, 0, 2, 3, 4]
    at:  [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
    bt:  [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
    prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]
    

    方法2 (自定义类和Comparator

    更具可读性将数据存储在自定义类中(例如DataEntry)。然后,您可以轻松地对对象数组(例如data)进行排序,而无需求助于难以阅读的代码:

    ArrayList<DataEntry> data = new ArrayList<>();
    data.add(new DataEntry(2, 2, "p1"));
    data.add(new DataEntry(0, 1, "p2"));
    data.add(new DataEntry(2, 3, "p3"));
    data.add(new DataEntry(3, 5, "p4"));
    data.add(new DataEntry(4, 4, "p5"));
    
    // sort data by 'at'
    data.sort(Comparator.comparing(d -> d.at));
    
    // print result
    data.forEach(d -> System.out.println(d.at + ", " + d.bt + ", " + d.prc));
    

    输出:

    0, 1, p2
    2, 2, p1
    2, 3, p3
    3, 5, p4
    4, 4, p5
    

    DataEntry类供参考:

    static class DataEntry {
        int at;
        int bt;
        String prc;
    
        public DataEntry(int at, int bt, String prc) {
            this.at = at;
            this.bt = bt;
            this.prc = prc;
        }
    }
    

    方法 3 (使用 indexOfComparator

    这只有在要排序的列表中没有重复项 (bt/prc) 时才稳定,因为 indexOf 总是返回列表中指定元素第一次出现的索引 (或 -1)。

    可以使用自定义ComparatorindexOf 对列表进行排序。我们可以在其他列表(bt/prc)中引用当前被比较元素(d)的相应位置的at中的值,以便对它们进行排序:

    ArrayList<Integer> at = new ArrayList<>(Arrays.asList(2, 0, 2, 3, 4));
    ArrayList<Integer> bt = new ArrayList<>(Arrays.asList(2, 1, 3, 5, 4));
    ArrayList<String> prc = new ArrayList<>(Arrays.asList("p1", "p2", "p3", "p4", "p5"));
    
    // sort 'bt' according to 'at'
    ArrayList<Integer> btSorted = new ArrayList<>(bt);
    btSorted.sort(Comparator.comparing(d -> at.get(bt.indexOf(d))));
    
    // sort prc according to 'at'
    ArrayList<String> prcSorted = new ArrayList<>(prc);
    prcSorted.sort(Comparator.comparing(d -> at.get(prc.indexOf(d))));
    
    // sort 'at' (just for inspection)
    ArrayList<Integer> atSorted = new ArrayList<>(at);
    Collections.sort(atSorted);
    
    // print result
    System.out.println(at + " => " + atSorted);
    System.out.println(bt + " => " + btSorted);
    System.out.println(prc + " => " + prcSorted);
    

    输出:

    at:  [2, 0, 2, 3, 4] => [0, 2, 2, 3, 4]
    bt:  [2, 1, 3, 5, 4] => [1, 2, 3, 5, 4]
    prc: [p1, p2, p3, p4, p5] => [p2, p1, p3, p4, p5]
    

    【讨论】:

      【解决方案2】:

      您有 2 个选项。 第一个很明显,我很好奇为什么它可能不适合你。

      选项 1)

      创建一个包含 at、bt、prc 值的类,实现 Comparable where compareTo(Foo other) 返回 at-other.at;

      选项 2)

      创建一个包含如下索引的新数组:

          ArrayList<Integer> indexes = List.of(0,1,2,3,4);
          indexes.sort(new Comparator(Integer o1, Integer o2) {
             return at[o1.intValue()]-at[o2.intValue()];
          })
      

      结果列表将类似于 {1,0,2,3,4} 然后:

          ArrayList<Integer> newAt = new ArrayList<>()
          ArrayList<Integer> newBt = new ArrayList<>()
          ArrayList<String> newPrc = new ArrayList<>()
      
          for(Integer i : indexes) {
            newAt.add(at.get(i));
            newBt.add(bt.get(i));
            newPrc.add(prc.get(i));
          }
      

      【讨论】:

      • 哦,伟大的思想都一样,忽略我的帖子 第一篇文章完全一样,但写得更好。
      猜你喜欢
      • 2012-09-07
      • 2021-08-21
      • 1970-01-01
      • 2016-03-21
      • 1970-01-01
      • 2013-07-09
      • 2020-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多