当前位置: 首页 > 面试题库 >

使用forEach在迭代过程中从集合中删除元素

訾安邦
2023-03-14
问题内容

最近,我编写此代码时并没有考虑太多:

myObject.myCollection.forEach { myObject.removeItem($0) }

其中myObject.removeItem(_),将删除该项目myObject.myCollection

现在看一下代码,我对为什么它甚至起作用感到困惑-我是否不应该得到类似的例外Collection was mutated while being enumerated?当使用常规的for-in循环时,甚至可以使用相同的代码!

这是预期的行为吗?还是我很幸运,它没有崩溃?


问题答案:

这确实是预期的行为–这是由于ArraySwift(以及标准库中的许多其他集合)是一种具有写时复制语义的值类型的事实。这意味着其基础缓冲区(间接存储)将在发生突变时被
复制 (并且,为优化起见,仅当未唯一引用时)。

当您使用SequenceforEach(_:)或)标准for in循环迭代(例如数组)时,将根据序列的makeIterator()方法创建迭代器,并next()反复应用其方法以顺序生成元素。

您可以考虑遍历序列,如下所示:

let sequence = [1, 2, 3, 4]
var iterator = sequence.makeIterator()

// `next()` will return the next element, or `nil` if
//  it has reached the end sequence.
while let element = iterator.next() { 
    // do something with the element
}

在使用的情况下Array,将an
IndexingIterator用作其迭代器–通过简单地
将该集合 与迭代的当前索引一起 存储,
即可遍历给定集合的元素。每次next()调用时,基集合都使用索引下标,然后递增索引,直到达到为止endIndex(您可以在此处看到其确切的实现)。

因此,当您要在循环中更改数组时,其底层缓冲区 不会被
唯一引用,因为迭代器也可以对其进行查看。这将强制复制缓冲区,myCollection然后使用该缓冲区。

因此,现在有两个数组–一个正在迭代的数组,另一个是您正在变异的数组。只要myCollection的缓冲区保持唯一引用,循环中的任何其他突变都不会触发另一个副本。

因此,这意味着在枚举值时对具有值语义的集合进行变异是绝对安全的。枚举将遍历整个集合–完全独立于您所做的任何突变,因为它们将在副本上完成。



 类似资料:
  • AFAIK,有两种方法: 迭代集合的副本 使用实际集合的迭代器 例如, 而且 有没有理由偏爱一种方法而不是另一种方法(例如,由于可读性的简单原因而偏爱第一种方法)?

  • 问题内容: AFAIK有两种方法: 遍历集合的副本 使用实际集合的迭代器 例如, 和 是否有任何理由偏爱一种方法(例如,出于可读性的简单原因而偏爱第一种方法)? 问题答案: 让我举几个例子,并提出一些避免方案。 假设我们有以下藏书 收集并删除 第一种技术是收集所有要删除的对象(例如,使用增强的for循环),并在完成迭代后删除所有找到的对象。 假设你要执行的操作是“删除”。 如果要“添加”此方法也可

  • 问题内容: 我正在对JRE 进行迭代,该JRE 强制执行快速失败迭代器概念,因此如果在迭代时修改了,则会抛出a ,而不是使用method。但是,如果对象满足条件,则需要删除该对象的“逻辑伙伴”。从而阻止伙伴也被处理。我怎样才能做到这一点?也许为此使用更好的收集类型? 例。 谢谢。 问题答案: 您要从列表中删除项目,然后继续在同一列表中进行迭代。您是否可以实施两步解决方案,即在步骤1中将要删除的项目

  • 问题内容: 我希望能够在迭代过程中从集合中删除多个元素。最初,我希望迭代器足够聪明,以使下面的幼稚解决方案能够正常工作。 但这会引发一个错误。 请注意,就我所知,iterator.remove()无法正常工作,因为我需要一次删除多个内容。还假设不可能确定“即时”删除哪些元素,但是可以编写该方法。在我的特定情况下,要确定要在迭代过程中删除的内容,将占用大量内存和处理时间。由于内存限制,也无法制作副本

  • 问题内容: 假设我有一个数字列表: 迭代时,如何从列表中删除元素(例如3)? 我尝试了以下代码,但没有成功: 有任何想法吗? 谢谢,博达·西多(Boda Cydo)。 问题答案: 最好的方法通常是建设性地进行-建立所需项目的新列表,而不要删除不需要的项目。例如: 列表理解建立所需的列表,并分配到“全名单切片” ,确保你 不 只是一个重新绑定的名字,但完全替换 内容 ,所以影响是恒等于你想要的“清除

  • 问题内容: 我在Web应用程序中通过Hibernate使用JPA。这是两个实体(仅显示吸气剂): 如您所见,并称为“一对多”。 现在,我需要加载一个实例,删除部分或全部子代并保存更改。以下是对我不起作用的代码: 在上面的示例中未删除子实体。现在,我必须手动为每个孩子打电话。 有没有更简单的方法来管理子代? 请注意,我不想使用特定于Hibernate的功能,只能使用纯JPA。 问题答案: 对于JPA