【问题标题】:Understanding this removeAll java method with arrayList用 arrayList 理解这个 removeAll java 方法
【发布时间】:2017-01-31 16:14:43
【问题描述】:

此方法的职责是从arrayList 中删除所有出现的值toRemove。剩余的元素应该只是向列表的开头移动(大小不会改变)。末尾的所有“额外”元素(尽管列表中出现了很多 toRemove)都应该用 0 填充。该方法没有返回值,如果列表没有元素,它应该没有效果。不能使用 ArrayList 类中的 remove()removeAll()

方法签名是:

public static void removeAll(ArrayList<Integer> list, int toRemove);

解决办法:

public static void removeAll(ArrayList<Integer> list, int toRemove) {
    for (int i = 0; i < list.size(); i++) {
        if (list.get(i) = toRemove) {
            for (int j = i + 1; j < list.size(); j++) {
                list.set(j - 1, list.get(j));
            }
            list.set(list.size() - 1, 0);
            i--;
        }
    }

我很理解第一个for 循环和if 语句。因为人们想逐一遍历整个arrayList,并且对于arrayList中存在数字的每个索引检查它是否是,实际上是toRemovee整数。在这之后我迷路了。

为什么还有一个for 循环?为什么我们在最后一个之后开始第二个for-loop? 为什么在第二个for 循环中我们使用list.set(),我知道set 方法接受两个参数,索引位置和子元素到该指定位置。为什么j-1?为什么在第二个循环结束后会有一行:list.set(list.size()-1, 0)?为什么是i--

有很多活动部件,我想了解其中的逻辑。

谢谢

【问题讨论】:

标签: java arraylist


【解决方案1】:

为什么还有一个for-loop?为什么我们在最后一个之后开始第二个for-loop?为什么在第二个 for 循环中我们使用list.set(),我知道 set 方法接受两个参数,即索引位置和子元素到该指定位置。为什么j - 1

该方法执行文档中所说的所有操作。 内部循环将元素左移一位。

for (int j = i + 1; j < list.size(); j++) {
    list.set(j - 1,       //The index before j (that is, j - 1) is set to...
            list.get(j)); //the current element.
    }
}

从找到的索引后的元素开始,将左边的元素设置为当前元素。最终,所有元素都会向左移动。

list.set(list.size() - 1, 0);

这会将最后一个元素设置为零。由于您的列表已删除一个元素,因此您需要删除最后一个元素,因为所有内容都已移动。

示例:

在这些示例中,^ 是 i,*j

0 1 2 3 4

假设我要删除 2。
首先,我会循环直到找到 2。

0 1 2 3 4
    ^ index: 2

现在,我将向左移动所有内容以删除该元素。因为我们要向左移动,所以我们需要从i + 1 开始(因此for 循环从i + 1 开始。

0 1 3 3 4
    ^ * (replaced the one before *)

接下来,我们再做一次。

0 1 3 4 4
    ^   *

现在我们完成了。

list.set(list.size() - 1, 0);

但是,最后剩下 4 个。我们需要删除它,因为我们删除了一个元素,并且列表短了一个元素。因此,我们将最后一个元素设置为零以将其删除(当然,这假定零不是列表中的有效值)。

注意:

我强烈建议使用list.remove(list.size() - 1) 而不是调用set。这实际上删除了最后一项,并没有留下“幻数”默认值。

为什么是i--

您需要i--,因为所有内容都已向左移动,因此您需要将索引 1 更新到左侧,即减一。 (实际上,您需要做的是在相同的索引处开始迭代,但是由于for-loop 每次迭代都会执行i++,您需要执行i-- 来“取消”它出来。)

【讨论】:

    【解决方案2】:

    为什么我们在最后一个 for 循环之后开始第二个 for 循环?

    每次发现一个事件,我们想要将arraylist的所有以下值左移1。

    为什么在第二个 for 循环中我们使用 list.set(),我明白了 该 set 方法接受两个参数,索引位置和 子到该指定位置的元素。为什么是 j - 1?

    j-1 用于左移 1 。

    为什么在第二个循环结束后会有一行:list.set(list. sise () - 1, 0) ?

    我们将值向左移动,但最后一个索引 (size-1) 处的值没有被任何东西替换,我们希望它是 0

    为什么是 i--?

    由于当前索引处的值已被另一个值覆盖,我们希望在同一索引处开始下一次迭代(i-- 补偿i++)。

    【讨论】:

      【解决方案3】:

      如果你想以 FP 风格做同样的事情;返回一个新列表而不是修改输入,您可以使用 Streams 来做到这一点。

      public static List<Integer> removeAll(ArrayList<Integer> list, int toRemove) {
          Integer rem = new Integer(toRemove); // OR change toRemove to Integer
          List<Integer> ret =  list.stream()
                         .filter(i -> !(i.equals(rem)))
                         .collect(Collectors.toList());
          return ret;
          //if you NEED to return ArrayList instead of List
          //return new ArrayList<>(ret);
      }
      

      【讨论】:

      • 如果您只需要修改传入的列表:更改方法以返回 void 和 list.clear(); list.addAll(ret); return ret;
      • 首先,您不应该使用new Integer(…)(在Java 9 中,此构造函数已被弃用)。使用自动装箱或显式Integer.valueOf(…)。但是,不清楚为什么您需要将int 转换为Integer。只需使用.filter(i -&gt; i != toRemove) 即可完美运行。即使.filter(i -&gt; !i.equals(toRemove)) 也可以,但这种从intInteger 的隐式转换是不必要的。
      猜你喜欢
      • 2021-12-16
      • 2014-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-18
      • 1970-01-01
      • 2015-05-01
      相关资源
      最近更新 更多