Java:带有Objects和null的Arrays.sort(...)

时间:2012-05-17 02:20:30

标签: java arrays sorting loops comparator

我正在使用Swing的应用程序。我有一个JTabbedPane,每个标签都被视为“页面”。每个页面包含4个普通面板(我将它们称为“视图”),这些面板按照2x2 GridLayout排列。

我想最小化页面数量,所以每次删除一个视图时,我都希望对所有页面中的所有视图进行重新排序(如果它更有意义,可以考虑二维数组),以便最后一页附近的视图并从那里删除,并被添加到靠近前面的页面。

考虑这个例子:

Object[][] array = new Object [][] {

    { new Object(), null, new Object(), new Object() },
    { null, null, new Object(), new Object() },
    { new Object(), new Object(), new Object(), new Object() }

};

如何对该数组进行排序,使其看起来更像:

Object[][] array = new Object[][] {

    { new Object(), new Object(), new Object(), new Object() },
    { new Object(), new Object(), new Object(), new Object() },
    { new Object(), null, null, null },

};

起初,我想过使用两个循环,一个从0到array.length,一个从array.length变为0.这个想法是:当一个从长度变为0接近0,它将检查从 0到长度的数组的索引是否为空。如果是这样,它会将非null元素放在包含null的索引中。

这种方法让我头疼,因为所有的循环所以我问了我的一位好朋友的建议。他提出了一个更优雅的解决方案:Arrays.sort(Object[][], Comparator)

此代码是结果:

    Object[][] array = new Object[][] { { new Object(), null, new Object(), new Object() }, { null, null, new Object(), new Object() }, { new Object(), new Object(), new Object(), new Object() } };

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            System.out.println("Before sorting: (i = " + i + " j = " + j + " null = " + (array[i][j] == null) + ")");
        }
    }

    Arrays.sort(array, new Comparator<Object>()
    {

        public int compare(Object a, Object b)
        {
            return a == null ? (b == null ? 0 : -1) : (b == null ? 1 : 0);
        }

    });

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            System.out.println("After sorting: (i = " + i + " j = " + j + " null = " + (array[i][j] == null) + ")");
        }
    }

输出结果为:

Before sorting: (i = 0 j = 0 null = false)
Before sorting: (i = 0 j = 1 null = true)
Before sorting: (i = 0 j = 2 null = false)
Before sorting: (i = 0 j = 3 null = false)
Before sorting: (i = 1 j = 0 null = true)
Before sorting: (i = 1 j = 1 null = true)
Before sorting: (i = 1 j = 2 null = false)
Before sorting: (i = 1 j = 3 null = false)
Before sorting: (i = 2 j = 0 null = false)
Before sorting: (i = 2 j = 1 null = false)
Before sorting: (i = 2 j = 2 null = false)
Before sorting: (i = 2 j = 3 null = false)
After sorting: (i = 0 j = 0 null = false)
After sorting: (i = 0 j = 1 null = true)
After sorting: (i = 0 j = 2 null = false)
After sorting: (i = 0 j = 3 null = false)
After sorting: (i = 1 j = 0 null = true)
After sorting: (i = 1 j = 1 null = true)
After sorting: (i = 1 j = 2 null = false)
After sorting: (i = 1 j = 3 null = false)
After sorting: (i = 2 j = 0 null = false)
After sorting: (i = 2 j = 1 null = false)
After sorting: (i = 2 j = 2 null = false)
After sorting: (i = 2 j = 3 null = false)

完全一样。 我还尝试将compare(Object, Object)实现替换为:

        public int compare(Object a, Object b)
        {
            if (a == null && b != null)
            {
                return -1;
            }
            if (b == null && a != null)
            {
                return 1;
            }
            return 0;
        }

......并取得了相同的成果。 我有点不知所措。这不是我不知道要做的事情,我无法解决如何为这样的问题实际创建解决方案。

我很感激任何帮助。无论你喜欢接近它,循环方法还是比较方法,我都很乐意看到它!

谢谢!

5 个答案:

答案 0 :(得分:2)

你的意思是

Object[][] array = new Object [][] { .. };

在您的情况下,您需要将二维数组转换为数组(一维数组)。排序新数组后,使用已排序的数组填充二维数组。

// convert to 1-D array
Object[] all = new Object[12];
int k = 0;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        all[k++] = array[i][j];
    }
}

// then sort the new array
Arrays.sort(all, yourComparator);

// then fill the 2-D array with the sorted array
k = 0;
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
        array[i][j] = all[k++];
    }
}

答案 1 :(得分:1)

数组的类型为Object[][]。因此,当您执行sort(array, theComparator)时,您正在安排Object[]内保留的三个array中的每一个。您对这三个数组中的每一个的内容进行排序。

由于Object[]中的三个array都不为空,因此您的比较器会在每次比较时返回零,因此Object[]保留在array内。

因此,您需要转换为Object的1-D数组,对其进行排序,然后将其分解为2-D数组。

答案 2 :(得分:1)

您的示例不清楚,显然与您的实际应用程序要求不符。 (对一堆无差别的Object实例进行排序是没有意义的!)

所以我要采取刺...并猜测你真的只是想把空值移到最后。 (其他非null元素已经排序,删除一个/一些不会改变它。或者它们根本不需要排序......)

如果是这种情况,那么简单的方法就是这样做:

  • 创建一个大小合适的临时一维数组
  • 按照您希望元素出现的顺序迭代2-D数组(例如,列中的行),并将非null元素复制到1-D数组中。
  • 再次迭代2-D阵列,从1-D阵列复制回来。

或者,如果您需要对非null元素进行排序,则可以使用Arrays.sort(Object[], int, int)在1-D数组中进行排序。选择边界以排除数组末尾的空值。这避免了创建理解null的“复杂”比较器的需要。


您当前的方法太复杂了......不必要的复杂代码是一个坏主意。

如果您的意图是在保留其他对象的顺序的同时将空值移动到最后,那么sort是一种昂贵的方法。 (它将与您定义的Comparator一起使用,因为sort(Object[] ...)方法被记录为执行稳定排序。但在这种情况下,我很想说它是不幸< / em>它有效。)

答案 3 :(得分:0)

您的代码失败的原因是您只是检查外部数组是否为null,您还应该检查外部数组的内容。

请参阅此代码:

import java.util.Arrays;
import java.util.Comparator;

public class Test2DArrayComparator {
    public static void main(String[] args) {
        Object[][] array = new Object[][]{
                {new Object(), null, new Object(), new Object()}, 
                {null, null, new Object(), new Object()},
                {new Object(), new Object(), new Object(), new Object()}
                };

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                System.out.println("Before sorting: (i = " + i + " j = " + j + " null = " + (array[i][j] == null) + ")");
            }
        }

        class ArrayComparator implements Comparator<Object>{

            @Override
            public int compare(Object a, Object b) {
                if(a == null && b == null){
                    return 0;
                } else if(a != null && b == null){
                    return 1;
                } else if(a == null && b != null){
                    return -1;
                } else {
                    return checkConents(((Object[])a), ((Object[])b));
                }
            }

        }
        Arrays.sort(array, new ArrayComparator());

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 4; j++) {
                System.out.println("After sorting: (i = " + i + " j = " + j + " null = " + (array[i][j] == null) + ")");
            }
        }

    }

    static int checkConents(Object[] first, Object[] second){
        for(int iDx = 0; iDx < first.length; iDx++){
            if(first[iDx] != null && second[iDx] == null){
                return -1;
            } else if(first[iDx] == null && second[iDx] == null){
                return 0;
            } else if(first[iDx] == null && second[iDx] != null){
                return 1;
            }
        }
        return -1;
    }
}

在检查外部数组checkContent的有效性之后调用以比较内容,同时注意checkContent假设两个数组的大小相同。

答案 4 :(得分:0)

您不希望代码中包含空值,您不希望检查null,您不想偶然发现null,并且您不希望null携带语义。

因此你不需要数组。

如果您想使用不同大小的Collection,请不要使用Arrays。

使用ArrayList,例如,易于使用,可变大小,无需使用空值。

如果从ArrayList中删除元素2:

   List <JPanel> al = new ArrayList <JPanel> ();
   al.add (new JPanel ());
   al.add (new JPanel ());
   al.add (new JPanel ());
   al.add (new JPanel ());

   al.remove (1); // 0-based numbering like in Arrays. 

现在元素2和3将向前滑动一个位置。你的阵列现在多久了?

   System.out.println (al.size ()); 

List中没有null,不需要对null进行测试,迭代?

   for (JPanel jp : al) 
        // do something to every jp.

不要在代码中使用null,但禁止它!

不要将Arrays用于不同大小的集合!