Java中在移除元素后缩短数组长度

5
注意: 以下是我的作业/任务,如果您不想回答,请随意忽略。
我想从一个字符串数组(集合)中删除/移除一个元素,但我不允许使用Collections等。现在我有这个:
void remove(String newValue) {

            for ( int i = 0; i < setElements.length; i++) {
               if ( setElements[i] == newValue ) {
                    setElements[i] = "";

               }
            }

       }   

我想要的是从数组中删除元素而不缩短数组长度。以下是输出结果,它基本上删除了索引为#1的元素。

D:\javaprojects>java SetsDemo
Enter string element to be added
A
You entered A
Set size is: 5
Member elements on index: 0 A
Member elements on index: 1 b
Member elements on index: 2 hello
Member elements on index: 3 world
Member elements on index: 4 six
Set size is: 5
Member elements on index: 0 A
Member elements on index: 1
Member elements on index: 2 hello
Member elements on index: 3 world
Member elements on index: 4 six

可能是如何在Java中从数组中删除对象?的重复问题。 - McDowell
5个回答

6
一旦创建了数组对象,就无法更改其长度。以下是来自JLS 10.2.数组变量的摘录:

一旦创建了数组对象,其长度将永远不会更改。要使数组变量引用不同长度的数组,必须将对不同数组的引用分配给变量。

这意味着对于这个问题,您需要分配一个比原始数组少一个元素的新数组,并复制剩余的元素。
如果您需要删除索引为k的元素,而原始数组有L个元素,则需要复制元素(上限是排除在外的):
  • [0,k)[0,k)k个元素)
  • [k + 1,L)[k,L-1)L-k-1个元素)。
  • 总共复制了L-1个元素

static String[] removeAt(int k, String[] arr) {
    final int L = arr.length;
    String[] ret = new String[L - 1];
    System.arraycopy(arr, 0, ret, 0, k);
    System.arraycopy(arr, k + 1, ret, k, L - k - 1);
    return ret;
}
static void print(String[] arr) {
    System.out.println(Arrays.toString(arr));       
}   
public static void main(String[] args) {
    String[] arr = { "a", "b", "c", "d", "e" };
    print(arr); // prints "[a, b, c, d, e]"

    arr = removeAt(0, arr);
    print(arr); // prints "[b, c, d, e]"

    arr = removeAt(3, arr);
    print(arr); // prints "[b, c, d]"

    arr = removeAt(1, arr);
    print(arr); // prints "[b, d]"

    arr = removeAt(0, arr);
    arr = removeAt(0, arr);
    print(arr); // prints "[]"
}

这里使用了System.arraycopy;如果不允许使用,您总是可以编写自己的代码。

static void arraycopy(String[] src, int from, String[] dst, int to, int L) {
    for (int i = 0; i < L; i++) {
        dst[to + i] = src[from + i];
    }
}

这是一个简单的实现,不处理src == dst的情况,但在这种情况下已经足够。

另请参阅


关于==用于比较String的说明

大多数情况下,使用==来比较String对象是错误的。你应该使用equals代替。

String ha1 = new String("ha");
String ha2 = new String("ha");
System.out.println(ha1 == ha2); // prints "false"
System.out.println(ha1.equals(ha2)); // prints "true"

参见


3
在Java中,一旦创建数组,其大小就无法更改。以下链接可以帮助您将现有项转移到新数组中:)请参见:System.arraycopyArray.copyOf(*)

2
“当然”可能对学生来说并不清楚。确实存在一些编程语言,其中数组可以调整大小... - masher
向学生解释东西可能会很有趣,因为他们知道或不知道的事情可能非常令人惊讶。有时候,即使是经验丰富的专业人士也会令人惊讶地不知道某些东西。但通常来说,如果他们值得信任,他们不知道的东西与学生不知道的东西非常不同。 - Jonathan M Davis

1

基本上,您需要创建一个新数组,其长度与旧数组的长度减1相同,然后您需要在循环中将有效元素从旧数组复制到新数组中,然后用新数组替换旧数组。

由于这是一份作业,因此细节被省略了。如需更多澄清,请随时发表评论。


1

setElements[i] = ""; 的作用只是改变数组中一个元素的值,它并没有从数组中实际删除任何内容。如果您正在使用集合类并调用了 remove(i),那么您实际上将从集合中删除该元素。但在这里,您只是改变了它的值。然而,在Java中,数组具有固定的大小,无法调整大小,因此无法从中删除元素。因此,解决方案是创建一个新数组,其长度比旧数组少一个,并将您想要保留的所有值复制到新数组中。所以:

  1. 创建一个长度为 setElements.length - 1 的新数组。

  2. setElements 中除您要删除的元素之外的所有元素都复制到新数组中。请注意,一旦到达您希望删除的元素的索引,两个数组中的索引将不再相等,而是相差一个。

  3. 如果您希望继续使用同一变量来引用您的数组,则将 setElements 设置为新数组。


0
void remove(String newValue) {
    if(setElements.length == 0) return;
    String [] array = new String[setElements.length-1];
    int j = 0;
    for ( int i = 0; i < setElements.length; i++) {
       if ( setElements[i] != newValue ) {
            array[j++] = setElements[i];
       }
    }
    setElements = array;
}

你可能是想在最后将 setElements 设置为 array,而不是反过来。 - Jonathan M Davis
如果 newValue 不在数组中会发生什么?(结果:IndexOutOfBoundsException)。其次,如果有多个条目匹配 newValue 会怎样?(结果数组末尾有 null 元素) - Kevin Brock
@Kevin Brock:即使 j 增加了 1,如果 newValue 不在数组中,array[j] 将不会被计算。 - zs2020
如果它不在数组中,那么代码将尝试从旧数组复制所有元素,但新数组比旧数组少一个元素,因此最后一个元素无法适应。所以,是的,在setElements中的每个元素中都会评估array[j]。 - Kevin Brock

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