1

我正在开发一个使用 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 到 length是空的。如果是这样,它将把非空元素放在包含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) + ")");
        }
    }

输出是:

排序前:(i = 0 j = 0 null = false)
排序前:(i = 0 j = 1 null = true)
排序前:(i = 0 j = 2 null = false)
排序前:(i = 0 j = 3 null = false)
排序前:(i = 1 j = 0 null = true)
排序前:(i = 1 j = 1 null = true)
排序前:(i = 1 j = 2 null = false)
排序前:(i = 1 j = 3 null = false)
排序前:(i = 2 j = 0 null = false)
排序前:(i = 2 j = 1 null = false)
排序前:(i = 2 j = 2 null = false)
排序前:(i = 2 j = 3 null = false)
排序后:(i = 0 j = 0 null = false)
排序后:(i = 0 j = 1 null = true)
排序后:(i = 0 j = 2 null = false)
排序后:(i = 0 j = 3 null = false)
排序后:(i = 1 j = 0 null = true)
排序后:(i = 1 j = 1 null = true)
排序后:(i = 1 j = 2 null = false)
排序后:(i = 1 j = 3 null = false)
排序后:(i = 2 j = 0 null = false)
排序后:(i = 2 j = 1 null = false)
排序后:(i = 2 j = 2 null = false)
排序后:(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;
        }

...并取得了相同的结果。我有点不知所措。这不是我没有知识去做的事情,我只是无法思考如何为这样的问题实际创建解决方案。

我会很感激任何帮助。无论您喜欢哪种方式,循环方法或比较器方法,我都希望看到它!

谢谢!

4

5 回答 5

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++];
    }
}
于 2012-05-17T02:41:43.590 回答
1

数组是类型Object[][]。因此,当您这样做时,您正在安排其中的sort(array, theComparator)三个。您没有对这三个数组中的每一个的内容进行排序。Object[]array

而且由于三个Object[]inarray中没有一个为 null,因此您的比较器在每次比较时都返回零,因此它们Object[]保持在array.

因此,您需要转换为 的一维数组Object,对其进行排序,然后将其分解为二维数组。

于 2012-05-17T02:39:40.983 回答
1

您的示例不清楚,显然不符合您的实际应用要求。(对一堆未区分的Object实例进行排序是没有意义的!)

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

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

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

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


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

而且,如果您的意图是将空值移到末尾,同时保留其他对象的顺序,那么sort这样做是一种昂贵的方法。(它将与Comparator您定义的方法一起使用,因为这些sort(Object[] ...)方法被记录为进行稳定的排序。但在这种情况下,我想说它很不幸地工作。)

于 2012-05-17T03:28:22.837 回答
0

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

请参阅此代码:

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假设两个数组的大小相同。

于 2012-05-17T02:50:56.890 回答
0

您不希望代码中有空值,不希望检查空值,不希望偶然发现空值,也不希望空值带有语义。

因此,您不需要数组。

如果您喜欢使用大小不同的集合,请不要使用数组。

以 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 ,但要禁止它!

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

于 2012-05-17T14:04:07.250 回答