基于第一列对二维数组进行排序

时间:2014-10-27 13:45:15

标签: java arrays sorting

我已经阅读了很多stackoverflow-posts和一些google-results,但还没有找到完美的东西。

基本上我有一个二维数组,第一行有点(整数),还有一个整数来标识"运行"这些点属于。我想根据点对数组进行排序,但在排序时不会丢失标识符。

编写该排序码的简短方法是什么?

之前:

string points[][] = 
        {
          { 12, 13, 10, 0, 0, 0 },
          { 1, 2, 3, 4, 5, 6 },      
        }

后:

string points[][] = 
        {
          { 13, 12, 10, 0, 0, 0 },
          { 2, 1, 3, 4, 5, 6 },      
        }

不是最好的例子,但我希望你明白这一点。

5 个答案:

答案 0 :(得分:0)

不幸的是,Java的Collections库缺少排序"并行数组的方法。创建一个类来保存您的运行,使用带有自定义比较器的类库对其进行排序,并将数据放回到您的数组中:

public class Run {
    public int points;
    public int runId;
}

Run[] runs = new Run[points[0].length];
for (int i = 0 ; i != runs.length ; i++) {
    Run r = new Run();
    r.points = points[0][i];
    r.runId = points[1][i];
    runs[i] = r;
}
Arrays.sort(runs, new Comparator<Run>() {
    public int compare(Run a, Run b) { 
        return -Integer.compare(a.points, b.points);
    }
});
for (int i = 0 ; i != runs.length ; i++) {
    points[0][i] = runs[i].points;
    points[1][i] = runs[i].runId;
}

Demo

答案 1 :(得分:0)

好的,通常我会建议使用有序的地图/数组列表,但如果这不是一个选项......

像第一行中的任何其他内容一样运行常规排序算法。但是,如果你必须进行交换,那么只需同时交换第二行的值,例如:

//loop through int i

if(points[i][0] < points[i+1][0]){
    int temp = points[i][0];
    points[i][0] = points[i + 1][0];
    points[i+1][0] = temp;

    temp = points[i][1];
    points[i][1] = points[i + 1][1];
    points[i+1][1] = temp;
}

美好而简单。

答案 2 :(得分:0)

使用简单的选择 - 排序:

public static void test()
{
        Integer points[][] = 
                {
                  { 12, 13, 10, 0, 0, 0 },
                  { 1, 2, 3, 4, 5, 6 },      
                };
        selectionSort(points[0], points[1]);
        System.out.println(Arrays.toString(points[0]));
        System.out.println(Arrays.toString(points[1]));
}

private static void swap(Integer[] arr, Integer[] arr2, int i, int minIndex)
{
    int tmp = arr[i];
    arr[i] = arr[minIndex];
    arr[minIndex] = tmp;

    tmp = arr2[i];
    arr2[i] = arr2[minIndex];
    arr2[minIndex] = tmp;       
}

// Use any sorting algorithm you like, just keep the swap method.
public static void selectionSort(Integer[] arr, Integer[] arr2) 
{
    int i, j, minIndex;
    int n = arr.length;
    for (i = 0; i < n - 1; i++) 
    {
        minIndex = i;

        for (j = i + 1; j < n; j++)
            if (arr[j] > arr[minIndex])
                minIndex = j;

        if (minIndex != i) 
        {
            swap(arr, arr2, i, minIndex);
        }
    }
}

答案 3 :(得分:0)

您可以交换索引,即将示例中的2x6数组存储为6x2数组,并通过点[y] [x]而不是点[x] [y]对其进行索引吗?

如果是这样,您可以使用常规排序函数和自定义比较器来比较每个子数组中的第一个元素:

Arrays.sort(points, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return o2[0] - o1[0];
    }
});

由于您不需要在所有相关行中手动交换元素,因此运行速度也会快得多。

因此,如果您可以重新构造其余代码以适应排序而不会产生其他重大性能影响,那么我会这样做。

否则,您可能必须实施其他答案中建议的手动排序,或者您可以在排序之前和之后转置数组,但我怀疑这会更快。

答案 4 :(得分:0)

恕我直言,好的方法是只对索引进行排序,但使用自定义比较器来比较值。这与0Andrea提出的this solution略有不同。不同之处在于,我们有两个不同的数组,一个用于索引,一个用于值,而不是具有多列行。

这样做的好处是你不必实现排序algorythm,只需使用JDK中本机实现的TimSort。这是一个Junit实现

public class SortTest {
    Integer points[][] = {
        { 12, 13, 10, 0, 0, 0 },
        { 1, 2, 3, 4, 5, 6 }, 
    };

    private Integer[] sort(Integer tab[][]) {
        IndexComparator<Integer> comparator = new IndexComparator<>(tab[0]);
        List<Integer> indexList = (List<Integer>) new ArrayList<>(Arrays.asList(tab[1]));
        Collections.sort(indexList, comparator);
        Integer[] result = new Integer[indexList.size()];
        return indexList.toArray(result);
    }

    private static class IndexComparator<T extends Comparable> implements Comparator<Integer> {
        Integer[] values;

        public IndexComparator(Integer[] values) {
            this.values = values;
        }

        @Override
        public int compare(Integer t, Integer t1) {
            return values[t1-1] - values[t-1];
        }
    }

    @Test
    public void test() {
        Integer[] result = sort(points);
        assertEquals(new Integer[]{2,1,3,4, 5, 6}, result);
        Integer[] values = new Integer[result.length];
        for (int i=0; i<values.length; i++) {
            values[i] = points[0][result[i] - 1];
        }
        assertEquals(new Integer[]{13,12,10,0,0,0}, values);
    }
}