这是我遇到问题找到解决方案的要求。
问题:
我有ArrayList,数据 20,10,30,50,40,10。
如果我们按升序排序,结果将 10,10,20,30,40,50。
但我需要结果为 3,1,4,6,5,2 。(排序后每个元素的索引)。
严格来说,即使列表中有重复的元素,这也应该有用。
请分享您解决此问题的想法/方法。
答案 0 :(得分: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);
}
}
答案 1 :(得分:0)
我的想法是在你的值旁边再创建一个属性调用索引(在aray的每个数据中)。它将保留您的旧索引,然后您可以将其取出使用。
答案 2 :(得分:0)
这是在Scala中写出的为每个元素添加索引的方法。这种方法最有意义。
list.zipWithIndex.sortBy{ case (elem, index) => elem }
.map{ case (elem, index) => index }
在Java中,您需要创建一个实现可竞争的新对象。
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的所有扫描),但如果您只需要执行几次就可以完成工作。
答案 3 :(得分:0)
建立Hury所说的内容,我认为我能看到的最简单的方法是创建一个看起来像这样的新数据类型:
public class Foo {
private Integer value;
private int origPosition;
private int sortedPosition;
/*Constructors, getters, setters, etc... */
}
还有一些psuedo代码,用于处理它......
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 :(得分:-1)
一种简单的方法是对列表进行排序;然后在原始列表上循环,找到排序列表中元素的索引,并将其插入另一个列表。
所以像
这样的方法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;
}
我没有测试过代码,可能需要对重复项进行更多处理。