【问题标题】:Selectively remove and delete objects from a NSMutableArray in Swift在 Swift 中从 NSMutableArray 中选择性地删除和删除对象
【发布时间】:2014-09-06 11:58:08
【问题描述】:

基本问题。在 Swift 中从可变数组中选择性地删除和删除项目的最佳方法是什么?

有些选项似乎不适合这种情况,例如在

中调用 removeObject
  • for 循环
  • 枚举块

和其他看起来一般都可以工作的人

  • for 循环 使用索引 + 调用 removeObjectAtIndex,甚至在循环内
  • for in loop 用于填充 arrayWithItemsToRemove,然后使用 originalArray.removeObjectsInArray(arrayWithItemsToRemove)
  • 使用 .filter 创建一个新数组似乎真的很好,但我不太确定替换整个原始数组的感觉如何

是否有推荐的、简单且安全的方法从数组中删除项目?我提到的其中一个或我缺少的东西?

在这方面获得不同的看法(有利和不利)或偏好会很好。我仍然很难选择合适的。

【问题讨论】:

  • 你说的是 Swift 的数组吗?还是关于 NSMutableArray?
  • 一个 NSMutableArray。感谢您的评论。我更改了标题以澄清这一点。

标签: swift nsmutablearray


【解决方案1】:

如果您想根据条件循环并从NSMutableArray 中删除元素,您可以以相反的顺序(从最后一个索引到零)循环数组,并删除满足条件的对象。

例如,如果您有一个整数数组并且想要删除可被三整除的数字,您可以像这样运行循环:

var array: NSMutableArray = [1, 2, 3, 4, 5, 6, 7];

for index in stride(from: array.count - 1, through: 0, by: -1) {
    if array[index] as Int % 3 == 0 {
        array.removeObjectAtIndex(index)
    }
}

以相反的顺序循环确保仍然要检查的数组元素的索引不会改变。相反,在前向模式下,如果您删除例如第一个元素,则先前位于索引 1 的元素将更改为索引 0,您必须在代码中考虑这一点。

出于性能原因,不建议在循环中使用removeObject(不适用于上述代码),因为它的实现会循环遍历数组的所有元素并使用isEqualTo 来确定是否删除反对与否。复杂度顺序从 O(n) 增加到 O(n^2) - 在最坏的情况下,数组的所有元素都被删除,数组在主循环中遍历一次,然后再次遍历数组的每个元素大批。所以所有基于枚举块的解决方案,for-in 等都应该避免,除非你有充分的理由。

filter 是一个不错的选择,我会使用它,因为:

  • 简洁明了:1 行代码,而不是基于索引的解决方案的 5 行(包括右括号)
  • 它的性能与基于索引的解决方案相当 - 它有点慢,但我认为没有那么多

但它可能并非在所有情况下都是理想的,因为正如您所说,它会生成一个新数组而不是就地操作。

【讨论】:

  • 对于 Swift 2.0,您需要 array.removeAtIndex(index)
【解决方案2】:

使用 NSMutableArray 时,您不应该在沿着可变数组本身循环时删除对象(除非向后循环,正如 Antonio 的回答所指出的那样)。

一种常见的解决方案是制作数组的不可变副本,对副本进行迭代,并通过调用“removeObject”或调用“removeObjectAtIndex”选择性地删除原始可变数组上的对象,但您必须计算索引,因为原始数组中的索引和副本中的索引将因删除而不匹配(每次删除对象时,您都必须减少“删除索引”)。

另一种解决方案(更好的)是将数组循环一次,创建一个带有要删除对象的索引的 NSIndexSet,然后在可变数组上调用“removeObjectsAtIndexes:”。

See documentation on NSMutableArray's "removeObjectsAtIndexes:" in Swift.

【讨论】:

    【解决方案3】:

    一些选项:

    • For 循环遍历索引并调用removeObjectAtIndex: 1) 您必须处理这样一个事实,即当您删除时,以下对象的索引将成为当前索引,因此您必须确保不增加这种情况下的索引;您可以通过向后迭代来避免这种情况。 2) 对removeObjectAtIndex 的每次调用都是 O(n)(因为它必须向前移动所有后续元素),所以算法是 O(n^2)。
    • For 循环构建一组要删除的元素,然后调用removeObjectsInArray:第一部分是 O(n)。 removeObjectsInArray 使用哈希表来测试元素是否有效移除;哈希表访问平均为 O(1),但最坏情况为 O(n),因此该算法平均为 O(n),但最坏情况为 O(n^2)。
    • 使用filter 创建一个新数组:这是 O(n)。它会创建一个新数组。
    • For 循环构建要删除的元素索引的索引集(或使用indexesOfObjectsPassingTest),然后使用removeObjectsAtIndexes 删除它们:我相信这是 O(n)。它不会创建新数组。
    • 使用基于测试块的谓词使用filterUsingPredicate:我相信这也是 O(n)。它不会创建新数组。

    【讨论】:

    • 那是 obj-c 方法不是吗?主题是关于 Swift 的
    • @Vinzius:引用的方法是NSMutableArray的方法。 NSMutableArray 是 Foundation 框架中的一个类,在 Objective-C 和 Swift 中都有。
    • 没错,我的错。我正在寻找 Array 方法 :-) 只尝试快速进行。
    猜你喜欢
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多