从数组中删除项目并缩小数组

43

我该如何从数组中删除一个元素,然后将数组大小调整为更小的尺寸呢?同样地,如果我需要添加另一个元素,如何增加数组的容量?


你的使用情况需要使用“数组”数据结构吗?看起来像是你在使用错误的工具。 - Ryan Fernandes
9个回答

29
Java数组的大小在分配时就已经固定,无法更改。
如果要“增加”或“缩小”现有数组的大小,则需要分配一个新的适当大小的数组,并复制数组元素。可以使用System.arraycopy(...)Arrays.copyOf(...)等方法进行复制,虽然循环复制也能实现,但可能会显得有些笨重。
如果要从数组中“删除”一个或多个项(真正意义上的删除,而不是只用null替换它们),则需要分配一个新的较小数组,并复制要保留的元素。
最后,可以通过将其赋值为null来“擦除”引用类型数组中的元素。但这会带来新的问题:
- 如果您使用了null元素表示某些含义,则无法这样做。 - 使用该数组的所有代码都必须以适当的方式处理可能存在的null元素。这会增加复杂性并导致出现潜在错误。
有第三方库提供了一些替代方案(例如Apache Commons中的ArrayUtils),但您可能需要考虑是否值得添加库依赖仅仅是为了实现自己可以用5-10行代码实现的方法。
更好的方法是使用List类而不是数组,这样会更简单(在许多情况下还更高效)。List类可以处理至少数组所能处理的“增长”,而且还有一些操作可用于在列表的任何位置插入和删除元素。
例如,ArrayList类使用一个数组作为后备存储,并根据需要自动扩展数组。它不会自动减小后备数组的大小,但您可以使用trimToSize()方法进行调整。
ArrayList l = ...
l.remove(21);
l.trimToSize();  // Only do this if you really have to.

1- 注意,显式的if (a[e] == null)检查本身很可能是"免费的",因为它们可以与当你引用a[e]的值时发生的隐式null检查结合起来。

2- 我说它在许多情况下更有效率,因为ArrayList使用一个简单的“加倍大小”策略来增长支持数组。这意味着如果通过重复追加来增加列表,则每个元素平均会额外复制一次。相比之下,如果你使用数组来做到这一点,你将平均要拷贝每个数组元素近N/2次。


18

你无法直接改变数组的大小,但是你可以创建一个新的数组并使用某些实用函数有效地将旧数组中的元素复制到新数组中,例如:

public static int[] removeElement(int[] original, int element){
    int[] n = new int[original.length - 1];
    System.arraycopy(original, 0, n, 0, element );
    System.arraycopy(original, element+1, n, element, original.length - element-1);
    return n;
}

然而,更好的方法是使用ArrayList(或类似的List结构)来存储您的数据,然后使用它的方法根据需要删除元素。


1
这段代码中有一个错误,会导致它始终抛出 NPE。我已经编辑了答案并进行了修复。 - Joel
第一个 System.arraycopy 方法调用不是必需的。 - Stuart

13

使用org.apache.commons.lang中的ArrayUtils.removeElement(Object[],Object)是迄今为止最简单的方法来实现这一点。

int[] numbers = {1,2,3,4,5,6,7};
//removing number 1
numbers =(int[])ArrayUtils.removeElement(numbers, 1);

2
这并不是真正改变数组的大小,而是创建了一个新数组。但没有其他办法,因为数组的大小无法更改。 - MrSmith42

8

由于数组在创建时分配了固定的大小,因此您唯一的选择是创建一个新数组,而不包含要删除的元素。

如果要删除的元素是最后一个数组项,则可以使用Arrays.copy轻松实现:

int a[] = { 1, 2, 3};
a = Arrays.copyOf(a, 2);

运行上述代码后,a将指向一个包含1、2的新数组。
否则,如果要删除的元素不是最后一个,则需要创建一个大小为size-1的新数组,并将除要删除的元素外的所有项复制到该数组中。
上述方法效率不高。如果您需要在内存中管理可变列表,请使用List。具体而言,LinkedList将在O(1)中从列表中删除一个项(理论上最快)。

对我来说,截取数组的最佳和最短工作解决方案。谢谢! - Ruwen

1

数组的大小是固定的,创建后无法调整大小。您可以通过将现有项设置为null来删除现有项:

objects[4] = null;

但是您将无法从数组中删除整个插槽并将其大小减小1。

如果您需要一个动态大小的数组,可以使用ArrayList。 使用它,您可以add()remove()对象,并且它会根据需要增长和缩小。


那么我能否创建一个新的数组,而不包含我想要删除的项? - Joe
@Joe:那也是一个可能的选项;看看其他答案。 - BoltClock

1
object[] newarray = new object[oldarray.Length-1];

for(int x=0; x < array.Length; x++)
{
  if(!(array[x] == value_of_array_to_delete))
  // if(!(x == array_index_to_delete))
   {
     newarray[x] = oldarray[x];
   }
}

创建数组后无法缩小其大小,但可以将其内容复制到另一个较小的数组中。


如果我只想忽略一个长度为640字节的数组中的最后一个字节,该怎么办... - Amit
那么你的实例化将会是 object[] new array = new object[oldarray.Length-2];,for循环会处理增量。 - Mike
我的意思是.. 即使我们只想忽略一个字节,我们是否需要创建一个新的数组.. 不能缩小数组吗? - Amit
不,如果你想要缩小数组的长度,你需要声明一个新的数组并将其内容复制过去。 - Mike

1

我创建了这个函数或类,我有点新手,但我的朋友也需要它,所以我创建了它:

public String[] name(int index, String[] z ){
    if(index > z.length){
        return z;
    } else {
        String[] returnThis = new String[z.length - 1];
        int newIndex = 0;
        for(int i = 0; i < z.length; i++){
            if(i != index){
                returnThis[newIndex] = z[i];
                newIndex++;
            }
        }
        return returnThis; 
    }
}

由于它相当相关,我想在这里发布它。


不。这与问题无关。它不会调整原始数组的大小。(而且,还有更简单的方法可以做到这一点。) - Stephen C

0

如果不使用System.arraycopy方法,您可以使用以下方法从数组中删除元素

    int i = 0;
    int x = 0;
    while(i < oldArray.length){
        if(oldArray[i] == 3)i++;

        intArray[x] = oldArray[i];
        i++;
        x++;
    }

其中3是您想要删除的值。


这还不完整,也没有真正回答问题。 - Stephen C

-3

不使用任何预定义函数,同时保证效率: --- >>

public static void Delete(int d , int[] array )
{       
    Scanner in = new Scanner (System.in);

    int i , size = array.length;

    System.out.println("ENTER THE VALUE TO DELETE? ");

     d = in.nextInt();

        for ( i=0;i< size;i++)
        {
                if (array[i] == d)
                        {


                            int[] arr3 =new int[size-1];
                            int[] arr4 = new int[i];
                            int[] arr5 = new int[size-i-1];

                                    for (int a =0 ;a<i;a++)
                                    {
                                        arr4[a]=array[a];
                                        arr3[a] = arr4[a];
                                    }
                                     for (int a =i ;a<size-1;a++)
                                     {
                                         arr5[a-i] = array[a+1];
                                         arr3[a] = arr5[a-i];

                                     }


                System.out.println(Arrays.toString(arr3));

                        }
                else System.out.println("************");    


        }

}

这并不按要求调整数组大小。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接