【问题标题】:Java: Remove an item from existing String ArrayJava:从现有的字符串数组中删除一个项目
【发布时间】:2018-04-14 13:58:13
【问题描述】:

我已经搜索了几个 SOF 线程,但似乎找不到我正在寻找的答案。他们中的大多数都提供了超出我迄今为止所学范围的代码的答案。

我已经尝试了很多不同的方法,但无法让它按照我需要的方式工作。

程序应该获取给定的数组,读取它,找到给定的 toRemove 项,然后重新打印没有 toRemove 项的数组。

我相信我的问题在于 removeFromArray 方法

public static void main(String[] args) 
{

    String[] test = {"this", "is", "the", "example", "of", "the", "call"};
    String[] result = removeFromArray(test, "the");
    System.out.println(Arrays.toString(result));
}

public static String[] removeFromArray(String[] arr, String toRemove)
{
    int newLength = 0;
    for(int i = 0; i < arr.length; i++)
    {    
        if(arr[i].contains(toRemove))
        {
            newLength++;
        }
    }
    String[] result = new String[arr.length-newLength];
    for(int i = 0; i < (result.length); i++)
    {
        if(arr[i].contains(toRemove))
        {

        }
        else
        {
            result[i] = arr[i];
        }
    }
    return result;
}

这是我的 java 课程中的一项作业,我们还没有学习列表(我在谷歌搜索中偶然发现的答案之一),所以这对我来说不是一个选择。

现在,它应该输出: [this, is, is, of, call]

目前正在输出:[this, is, null, example, of]

我们将不胜感激任何和所有的帮助!

【问题讨论】:

  • 您可能想使用.equals 而不是.contains。如果你使用.contains,你的方法也会从数组中删除"the dog""absinthe"等。

标签: java arrays string methods


【解决方案1】:

您需要在第二个循环中使用 2 个索引,因为您正在迭代两个长度不同的数组(输入数组和输出数组)。

此外,newLength 是一个令人困惑的名称,因为它不包含新的长度。它包含输入数组长度和输出数组长度之间的差异。您可以更改其值以匹配其名称。

int newLength = arr.length;
for(int i = 0; i < arr.length; i++)
{    
    if(arr[i].contains(toRemove))
    {
        newLength--;
    }
}
String[] result = new String[newLength];
int count = 0; // count tracks the current index of the output array
for(int i = 0; i < arr.length; i++) // i tracks the current index of the input array
{
    if(!arr[i].contains(toRemove)) {
        result[count] = arr[i]; 
        count++;
    }
}
return result;

【讨论】:

    【解决方案2】:

    以下代码删除所有出现的提供的字符串。

    请注意,我添加了几行来验证输入,因为如果我们将空数组传递给您的程序,它将失败。您应该始终验证代码中的输入。

    public static String[] removeFromArray(String[] arr, String toRemove) {
    
        // It is important to validate the input
        if (arr == null) {
            throw new IllegalArgumentException("Invalid input ! Please try again.");
        }
    
        // Count the occurrences of toRemove string.
        // Use Objects.equals in case array elements or toRemove is null.
        int counter = 0;
        for (int i = 0; i < arr.length; i++) {
            if (Objects.equals(arr[i], toRemove)) {
                counter++;
            }
        }
    
        // We don't need any extra space in the new array
        String[] result = new String[arr.length - counter]; 
        int resultIndex = 0; 
    
        for (int i = 0; i < arr.length; i++) {
            if (!Objects.equals(arr[i], toRemove)) {
                result[resultIndex] = arr[i];
                resultIndex++;
            }
        }
    
        return result;
    }
    

    【讨论】:

    • Objects.isNull 主要用作过滤谓词(例如stream.filter(Objects::isNull).count()。最好使用arr == nulltoRemove == null 作为Objects.isNull 只执行== null
    • 另外,arr.length == 0 时没有理由抛出错误。毕竟,Collection.remove 在集合为空时效果很好。
    • 调用者实际上可能想通过调用removeFromArray(arr, null) 来删除null 元素。最好使用Objects.equals(arr[i], toRemove) 来容忍数组中的null 值和toRemove
    • 我已经相应地修改了答案。感谢您的建议。虽然我只是看了一下isNull方法的源代码。它只是检查元素是否为空,没什么特别的。
    • 谢谢!我输入了我所说的Objects.equals 支票。
    【解决方案3】:

    @Eran 在您的代码中指出的错误可以解决您的问题。但我将讨论另一种方法。

    现在,您首先遍历整个数组以查找要删除的出现次数,然后遍历数组以删除它们。你为什么不只是迭代数组,只是为了删除它们。 (我知道,您的第一个循环是帮助您确定输出数组的大小,但如果您使用一些 List(如 ArrayList 等),则不需要它。)

    List<String> resultList = new ArrayList<String>();
    for(int i = 0; i < arr.length; i++)
    {
        if(!arr[i].contains(toRemove))
        {
            resultList.add(arr[i]);
        }
    }
    

    你可以返回resultList,但是如果你真的需要返回一个数组,你可以将resultList转换成这样的数组:

    String [] resultArray = resultList.toArray(new String[resultList.size()]);
    

    然后返回这个数组。现场查看此方法here on ideone

    【讨论】:

    • 确实有相同的区别,尽管这是一种更简单的方法。根据给定机器上读取和写入的相对时间,OP 方法可能会更快。
    • 我认为不是。因为在 OPs 方法中,两个循环中有一个 contains 操作。花费的总时间是(2 * N * time taken by contains)N 是输入数组长度。但是在这种方法中,它是(N * time taken by contains) + (N * time taken to copy),而contains 操作比单纯的复制操作要昂贵得多。
    • 其实你是对的。实际上OP可能不应该使用contains,而是equals
    • 请注意,复制所花费的时间实际上是 O(N),而不是真正的 N,因为定期调整 ArrayList 的大小会产生一些成本。
    • 是的,当然不能忽略ArrayList调整大小的时间。
    【解决方案4】:

    试试这个 Java8 版本

        List<String> test = Arrays.asList("this", "is", "the", "example", "of", "the", "call");
    
        test.stream()
            .filter(string -> !string.equals("the"))
            .collect(Collectors.toList())
            .forEach(System.out::println);
    

    【讨论】:

      【解决方案5】:

      你可以改用 Java Stream,它会给你预期的结果,你的代码也会更清晰,更小。

      请参阅下面我写的解决您问题的方法。

      public static String[] removeFromArray(String[] arr, String toRemove) {
          return Arrays.stream(arr)
            .filter(obj -> !obj.equals(toRemove))
            .toArray(String[]::new);
      }
      

      如果您对 java Stream 不熟悉,请参阅doc here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-28
        • 1970-01-01
        • 2013-03-02
        • 1970-01-01
        • 1970-01-01
        • 2017-02-10
        • 2016-09-06
        • 2017-03-16
        相关资源
        最近更新 更多