【问题标题】:Index related sorting problem in JavaJava中与索引相关的排序问题
【发布时间】:2011-09-15 04:42:25
【问题描述】:

这是我在寻找解决方案时遇到问题的要求。

问题:

我有 ArrayList 的数据 20、10、30、50、40、10。

如果我们按升序排序,结果将是10、10、20、30、40、50。

但我需要结果为 3, 1, 4, 6, 5, 2。(排序后每个元素的索引)。

严格来说,即使列表中有重复元素,这也应该有效。

请分享您解决此问题的想法/方法。

【问题讨论】:

  • 那么你关心相等元素的顺序吗?或者您还想通过特定的排序顺序告诉我们什么?元素的类型是什么?你试过Collections.sort()吗?
  • 元素是整数类型。我需要排序后所有元素的新索引。我不需要排序列表,因此我认为 Collections.sort() 不起作用。

标签: java sorting indexing


【解决方案1】:

这是我的解决方案。我们定义了一个比较器来根据列表中的相应对象对索引列表进行排序。这给了我们一个索引列表,它实际上是一个映射:indices[i] = x 表示原始列表中位置x 的元素位于排序列表中的元素i。然后我们可以很容易地创建一个反向映射。

输出是从 0 开始的索引:[2, 0, 3, 5, 4, 1]

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class LookupComparator<T extends Comparable<T>> implements Comparator<Integer> {
    private ArrayList<T> _table;
    public LookupComparator(ArrayList<T> table) { 
        _table = table; 
    }
    public int compare(Integer o1, Integer o2) {
        return _table.get(o1).compareTo(_table.get(o2));
    }
}

public class Test {

    public static <T extends Comparable<T>> ArrayList<Integer> indicesIfSorted(ArrayList<T> list) {
        ArrayList<Integer> indices = new ArrayList<Integer>();
        for (int i = 0; i < list.size(); i++)
            indices.add(i);
        Collections.sort(indices, new LookupComparator(list));

        ArrayList<Integer> finalResult = new ArrayList<Integer>();
        for (int i = 0; i < list.size(); i++)
            finalResult.add(0);
        for (int i = 0; i < list.size(); i++)
            finalResult.set(indices.get(i), i);
        return finalResult;
    }

    public static void main(String[] args) {

        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(20);
        list.add(10);
        list.add(30);
        list.add(50);
        list.add(40);
        list.add(10);

        ArrayList<Integer> indices = indicesIfSorted(list);
        System.out.println(indices);


    }


}

【讨论】:

    【解决方案2】:

    我的想法是在您的值旁边(在 aray 的每个数据中)再创建 1 个属性调用索引。它将保存您的旧索引,然后您可以将其取出使用。

    【讨论】:

    • 你能详细说明一下吗?正如我在问题中解释的那样,我需要列表中元素的新索引
    【解决方案3】:

    根据 Hury 所说,我认为最简单的方法是创建一个看起来像这样的新数据类型:

    public class Foo {
        private Integer value;
        private int origPosition;
        private int sortedPosition;
        /*Constructors, getters, setters, etc... */
    }
    

    还有一些用于处理它的伪代码......

    private void printSortIndexes(ArrayList<Integer> integerList) {
        // Create an ArrayList<Foo> from integerList - O(n)
        // Iterate over the list setting the origPosition on each item - O(n)
        // Sort the list based on value
        // Iterate over the list setting the sortedPosition on each item - O(n)
        // Resort the list based on origPositon
        // Iterate over the lsit and print the sortedPositon - O(n)
    }
    

    这不会花很长时间来实施,但效率极低。您投入了额外的 4 O(n) 操作,每次您从列表中添加或删除任何内容时,存储在对象中的所有位置都将失效 - 因此您必须重新计算所有内容。它还要求您对列表进行两次排序。

    因此,如果这是一个小数据集的一次性小问题,它会起作用,但如果您尝试制作一些可以长时间使用的东西,您可能想尝试一种更优雅的方法来去做吧。

    【讨论】:

      【解决方案4】:

      这是为每个元素添加索引的方法,用 Scala 编写。这种方法最有意义。

      list.zipWithIndex.sortBy{ case (elem, index) => elem }
        .map{ case (elem, index) => index }
      

      在 Java 中,您需要创建一个实现 comperable 的新对象。

      class IndexedItem implements Comparable<IndexedItem> {
          int index;
          int item;
      
          public int compareTo(IndexItem other) {
              return this.item - other.item;
          }
      }
      

      然后您可以构建一个 IndexedItems 列表,使用 Collection.sort 对其进行排序,然后提取索引。

      您也可以在原始列表中使用 Collections.sort,然后调用 indexOf。

      for (int elem : originalList) {
          int index = newList.indexOf(elem);
          newList.get(index) = -1; // or some other value that won't be found in the list
          indices.add(index);
      }
      

      这会很慢(对 indexOf 的所有扫描),但如果您只需要执行几次就可以完成工作。

      【讨论】:

      • 我认为这不会像所说的那样工作。张贴者希望您按元素排序,而不是按索引,因此您的 compareTo 应该比较项目而不是索引。
      • 是的,我不敢相信我这样做了两次...已在我的帖子中修复。
      【解决方案5】:

      一种简单的方法是对列表进行排序;然后在原始列表上循环,找到排序列表中元素的索引并将其插入到另一个列表中。

      这样的方法

      public List<Integer> giveSortIndexes(List<Integer> origList) {
          List<Integer> retValue = new ArrayList<Integer>();
          List<Integer> originalList = new ArrayList<Integer>(origList);
          Collections.sort(origList);
          Map<Integer, Integer> duplicates = new HashMap<Integer, Integer>();
          for (Integer i : originalList) {
              if(!duplicates.containsKey(i)) {
                  retValue.add(origList.indexOf(i) + 1);
                  duplicates.put(i, 1);
              } else {
                  Integer currCount = duplicates.get(i);
                  retValue.add(origList.indexOf(i) + 1 + currCount);
                  duplicates.put(i, currCount + 1);
              }
          }
          return retValue;
      }
      

      我还没有测试代码,它可能需要对重复项进行更多处理。

      【讨论】:

      • downvoters 应该总是发表评论,无论如何我已将此标记为一个简单的示例。现在我被否决了,我在 eclipse 上检查了它,更新了我的例子,它似乎有效。仍然不是最好的,但足以给出一个想法。
      猜你喜欢
      • 2018-10-31
      • 2019-03-12
      • 1970-01-01
      • 2011-05-05
      • 2015-05-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      相关资源
      最近更新 更多