3

快速问题:我有一个数组double[]array=new double [10],其中有随机双精度数,例如在 0 到 20 之间。我想要的是得到另一个数组int []resultingArray=new int [array.length],每个值 int 是array[]排序形式从最大数字到最小数字的双精度值的索引。由于我的英语很烂,这里是一个“图表”:

数组 = (2, 6, 3) _ __ _ _结果数组 = (1, 2, 0)

这是一道考试题。双打是学生的 GPA,它要求一个方法返回一个数组,该数组由从最好的学生到最差的学生的 ID(在我的代码中是 double[]array 的索引)组成。

4

6 回答 6

1

有很多使用Maps 的解决方案,我将提出一个仅使用数组的替代方案:

public int[] getIndices(double[] originalArray)
{
    int len = originalArray.length;

    double[] sortedCopy = originalArray.clone();
    int[] indices = new int[len];

    // Sort the copy
    Arrays.sort(sortedCopy);

    // Go through the original array: for the same index, fill the position where the
    // corresponding number is in the sorted array in the indices array
    for (int index = 0; index < len; index++)
        indices[index] = Arrays.binarySearch(sortedCopy, originalArray[index]);

    return indices;
}

然而,这是非常低效的。

于 2013-01-06T22:14:10.633 回答
0

Here's how I would do it:

  • Put all of the elements of array in a Map<Integer, Double> that maps the index to the value.

  • Put all of the elements of the entrySet() of this map into a list and sort that list by values.

  • Form an array out of the keys of the newly sorted list of entries.


public static int[] getIndicesInOrder(double[] array) {
    Map<Integer, Double> map = new HashMap<Integer, Double>(array.length);
    for (int i = 0; i < array.length; i++)
        map.put(i, array[i]);

    List<Entry<Integer, Double>> l = 
                           new ArrayList<Entry<Integer, Double>>(map.entrySet());

    Collections.sort(l, new Comparator<Entry<?, Double>>() {
            @Override
            public int compare(Entry<?, Double> e1, Entry<?, Double> e2) {
                return e2.getValue().compareTo(e1.getValue());
            }
        });

    int[] result = new int[array.length];
    for (int i = 0; i < result.length; i++)
        result[i] = l.get(i).getKey();

    return result;
}

public static void main(String[] args) {
    double[] array = { 1.1, 2.2, 3.3, 4.4, 3.3 };

    System.out.println(Arrays.toString(getIndicesInOrder(array)));
}
[3, 2, 4, 1, 0]
于 2013-01-06T21:29:19.177 回答
0

也许是这样的:

import java.util.*;

public class Test
{
    static Integer[] getIndicesInOrder(Integer[] array)
    {
        Integer[] c = array.clone();
        Arrays.sort(c, Collections.reverseOrder());

        List<Integer> l = Arrays.asList(array);

        for (int i = 0; i < array.length; ++i)
        {
            c[i] = l.indexOf(c[i]);
        }

        return c;
    }

    public static void main(String[] args)
    {
        Integer[] array = {2,6,3};

        System.out.println(Arrays.toString(getIndicesInOrder(array)));
    }
}
于 2013-01-06T21:11:35.937 回答
0

您可以使用自定义Comparator比较各个索引处的等级数组中的值,

import java.util.*;

public class GradeComparator implements Comparator<Integer> {
    private double[] grades;
    public GradeComparator(double[] arr) {
        grades = arr;
    }
    public int compare(Integer i, Integer j) {
        return Double.compare(grades[j], grades[i]);
    }
}

并使用它对索引数组进行排序Comaprator

导入 java.util.*;

public class SortGrades {
    public static void main(String[] args) {
        double[] grades = { 2.4, 6.1, 3.9, 4.8, 5.5 };
        Integer[] ranks = new Integer[grades.length];
        for(int i = 0; i < ranks.length; ++i) {
            ranks[i] = i;
        }
        Comparator<Integer> gc = new GradeComparator(grades);
        Arrays.sort(ranks, gc);
        for(int i = 0; i < ranks.length; ++i) {
            System.out.println((i+1) + ": " + ranks[i] + ", grade: " + grades[ranks[i]]);
        }
    }
}

输出

1: 1, grade: 6.1
2: 4, grade: 5.5
3: 3, grade: 4.8
4: 2, grade: 3.9
5: 0, grade: 2.4

如预期的。

于 2013-01-06T22:20:26.570 回答
0

如果学生的分数是随机的,你可以这样做(这在现实世界中没有多大意义,因为你不能/不给学生打分精确到15位数字;)

public static int[] sortWithIndex(double[] results) {
    class ScoreIndex implements Comparable<ScoreIndex> {
        final double score;
        final int index;

        ScoreIndex(double score, int index) {
            this.score = score;
            this.index = index;
        }

        @Override
        public int compareTo(ScoreIndex o) {
            int cmp = Double.compare(score, o.score);
            return cmp == 0 ? Integer.compare(index, o.index) : cmp;
        }
    }
    List<ScoreIndex> list = new ArrayList<>();
    for (int i = 0; i < results.length; i++) list.add(new ScoreIndex(results[i], i));
    Collections.sort(list);
    int[] indexes = new int[results.length];
    for (int i = 0; i < list.size(); i++) indexes[i] = list.get(i).index;
    return indexes;
}

如果您对学生进行评分以限制精度,请说您只能做到 < 6 位数

public static void sortWithIndex(double[] results) {
    for(int i = 0; i < results.length; i++)
        results[i] = results[i] * results.length * 1e6 + i;
    Arrays.sort(results);
}

现在results按值的顺序包含所有原始值和它们来自的索引,如果有重复,则较低的索引在前。

于 2013-01-06T21:05:06.880 回答
0

这是一道考试题。双打是学生的 GPA,它要求一个方法返回一个数组,该数组由从最好的学生到最差的学生的 ID(在我的代码中是 double[]array 的索引)组成。

我会用地图来做。<ID, Doubles>. 我们不能直接使用 TreeMap,因为它是按 Key 排序的。我们想按价值(那些双打)排序。但是,我们可以对此做一些技巧,以制作我们自己的比较器 impl。按值对地图进行排序。

我在一个junit测试类中写的,

@Test
public void testArray() {
    final double[] array = new double[] { 1.1, 2.2, 3.3, 4.4, 3.3 };
    final int[] result = new int[array.length];

    final Map<Integer, Double> map = new HashMap<Integer, Double>();
    for (int i = 0; i < array.length; i++) {
        map.put(i, array[i]);
    }
    final List<Map.Entry> list = new LinkedList<Map.Entry>(map.entrySet());
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(final Object o1, final Object o2) {
            return 0 - ((Comparable) ((Map.Entry) o1).getValue()).compareTo(((Map.Entry) o2).getValue());
        }
    });
    for (int i = 0; i < list.size(); i++) {

        result[i] = (Integer) list.get(i).getKey();
    } 

    //here we have result, to test it:
    for (final int element : result) {
        System.out.println(element);
    }
}

它打印:

    3
    2
    4
    1
    0
于 2013-01-06T21:46:46.253 回答