2011-02-01 120 views
48

假设用户输入的阵列,例如:排序后获取数组的索引?

Array = {France, Spain, France, France, Italy, Spain, Spain, Italy} 

其中我知道它

长度index阵列将是:

index = {0, 1, 2, 3, 4, 5, 6, 7} 

现在,使用排序之后Arrays.sort(Array);

newArray会像:

newArray = {France, France, France, Italy, Italy, Spain, Spain, Spain} 

newIndex将是:

newIndex = {0, 2, 3, 4, 7, 1, 5, 6} 

的问题是:我怎么能找到输入数组的newIndex

在此先感谢

+0

类似到http://stackoverflow.com/questions/4839915/sorting-a-list-based-on-another-lists-values-java/4839994#4839994但更明确的定义。 – maaartinus 2011-02-01 05:49:01

回答

70

不要对数组开始排序。对索引数组进行排序,传入一个比较器,将比较值通过作为索引进行比较。所以你最终得到newIndex作为排序的结果,并且从那里到实际项目的排序数组很简单。不可否认,这意味着以自定义方式对整数数组进行排序 - 这意味着使用Integer[]和标准Java库,或者具有“IntComparator”接口的第三方库,它可以与sort(int[], IntComparator)类型的方法。

编辑:好的,这里是一个示例比较。为了简单起见,我假设你只想对一个“原始”字符串进行排序......而且我不打扰无效性测试。

public class ArrayIndexComparator implements Comparator<Integer> 
{ 
    private final String[] array; 

    public ArrayIndexComparator(String[] array) 
    { 
     this.array = array; 
    } 

    public Integer[] createIndexArray() 
    { 
     Integer[] indexes = new Integer[array.length]; 
     for (int i = 0; i < array.length; i++) 
     { 
      indexes[i] = i; // Autoboxing 
     } 
     return indexes; 
    } 

    @Override 
    public int compare(Integer index1, Integer index2) 
    { 
     // Autounbox from Integer to int to use as array indexes 
     return array[index1].compareTo(array[index2]); 
    } 
} 

你会使用这样的:你可以这样做

String[] countries = { "France", "Spain", ... }; 
ArrayIndexComparator comparator = new ArrayIndexComparator(countries); 
Integer[] indexes = comparator.createIndexArray(); 
Arrays.sort(indexes, comparator); 
// Now the indexes are in appropriate order. 
1

的方法之一是原指数和国名裹成一个单独的类。然后根据名称对数组进行排序。这样,您的原始索引将被保留。

+0

你能举个例子吗? – 2011-02-01 05:36:50

4
TreeMap<String,Int> map = new TreeMap<String,Int>(); 
for(int i : indexes) { 
    map.put(stringarray[i], i); 
} 

现在迭代器来map.values()来检索排序顺序的索引,并在map.keySet()来获取字符串或超过map.entrySet()来获取字符串指数,双。

+3

由于重复,这不起作用。 SortedMultimap在这里没有帮助。 – maaartinus 2011-02-01 05:51:33

+0

@maaartinus可以使用TreeMap >的地图。首先,您将所有字符串添加到地图中,并且列表为空,然后遍历原始列表并将索引添加到地图项目列表中。 – 2015-10-10 21:26:37

+0

然后,您只需遍历值并为列表中的每个索引插入一个元素即可。它会很稳定。 – 2015-10-10 21:27:15

1

乍一看会给出映射它们就像

Map <Integer, String> map = new HashMap<Integer, String>(); 
map.put(0, "France"); 
map.put(1, "Spain"); 
map.put(2, "France"); 

,然后通过价值like that对它们进行排序,然后你就可以知道他们的索引和值(键,值)只打印地图

Iterator mapIterator = map.keySet().iterator(); 

while (mapIterator .hasNext()) { 
    String key = mapIterator.next().toString(); 
    String value = map.get(key).toString(); 

    System.out.println(key + " " + value); 
} 
10

与Java 8个流API实现这一目标的简洁的方式,

final String[] strArr = {"France", "Spain", "France"}; 
int[] sortedIndices = IntStream.range(0, strArr.length) 
       .boxed().sorted((i, j) -> strArr[i].compareTo(strArr[j])) 
       .mapToInt(ele -> ele).toArray(); 
2

我根据@ Skeet的代码进行了以下操作。我认为这是多一点OOPie。我不知道。

public static <T extends Comparable<T>> List<Integer> sortIndex(List<T> in) { 
    ArrayList<Integer> index = new ArrayList<>(); 
    for (int i = 0; i < in.size(); i++) { 
     index.add(i); 
    } 

    Collections.sort(index, new Comparator<Integer>() { 
     @Override 
     public int compare(Integer idx1, Integer idx2) { 
      return in.get(idx1).compareTo(in.get(idx2)); 
     } 
    }); 

    return index; 
} 

相反实现具有用于进入的不同对象的比较代码排序和索引之类的,原来的数组中的对象必须实现Comparable接口。看起来许多感兴趣的对象具有自然排序并且已经实现了Comparable接口。

public static void main(String[] args) { 

    List<Integer> a1 = new ArrayList<>(Arrays.asList(2, 3, 9, 4, 1)); 
    // Just pass in the list to have its indexes sorted by the natural ordering 
    List<Integer> idx = sortIndex(a1); 

    List<Double> a2 = new ArrayList<>(Arrays.asList(1.0, 5.3, 5.2, -3.1, 0.3)); 
    idx = sortIndex(a2); 

    List<numBits> a3 = new ArrayList<>(); 
    for (int i = 0; i < 10; i++) { 
     a3.add(new numBits(i)); 
    } 

    // If you need to sort the indexes of your own object, you must implement 
    // the Comparable Interface. 
    idx = sortIndex(a3); 
} 

static class numBits implements Comparable<numBits> { 
    private int a; 

    public numBits(int i) { 
     a = i; 
    } 

    public String toString() { 
     return Integer.toString(a); 
    } 

    // Sort by the total number of bits in the number. 
    @Override 
    public int compareTo(numBits that) { 
     if (Integer.bitCount(this.a) < Integer.bitCount(that.a)) 
      return -1; 
     if (Integer.bitCount(this.a) > Integer.bitCount(that.a)) 
      return 1; 
     return 0; 
    } 
} 
1

如果具有重复排序基本float或具有正值INT阵列的情形下,然后如下面的方法产生好得多(X3〜X4)的速度相比,使用任何比较:

long time = System.currentTimeMillis(); 
for (int i = 0; i < iters; i++) {   
    float[] array = RandomUtils.randomFloatArray(-1, 1, 3000); 
    long[] valueKeyPairs = new long[array.length]; 
    for (int j = 0; j < array.length; ++j) { 
     valueKeyPairs[j] = (((long) Float.floatToIntBits(array[j])) << 32) | (j & 0xffffffffL); 
    } 
    Arrays.sort(valueKeyPairs); 
    /**Then use this to retrieve the original value and index*/ 
    //long l = valueKeyPairs[j]; 
    //float value = Float.intBitsToFloat((int) (l >> 32)); 
    //int index = (int) (l); 
} 
long millis = System.currentTimeMillis() - time;