从Swift中的NSMutableArray中有选择地删除和删除对象

时间:2014-09-06 11:58:08

标签: swift nsmutablearray

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

有些选项似乎不适合这样做,比如在

中调用 removeObject
  • for in loop
  • 枚举块

和其他似乎一般工作的人

  • for loop 使用索引+调用 removeObjectAtIndex ,即使在循环内
  • for in循环,用于填充 arrayWithItemsToRemove ,然后使用originalArray。 removeObjectsInArray(arrayWithItemsToRemove)
  • 使用 .filter 创建一个新数组似乎非常好,但我不太确定我对更换整个原始数组的感受

是否有推荐的,简单而安全的方法从阵列中删除项目?其中一个我提到的或我失踪的东西?

获得不同的(有利有弊)或偏好是很好的。我仍然很难选择合适的人。

3 个答案:

答案 0 :(得分:11)

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

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

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行(包括右括号)
  • 它的表现与基于指数的解决方案相当 - 它有点慢,但我认为不是那么多

但在所有情况下,它可能并不理想,因为正如您所说,它会生成一个新数组,而不是在适当的位置运行。

答案 1 :(得分:7)

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

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

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

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

答案 2 :(得分:4)

部分选项:

  • 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)。它不会创建新阵列。