我想枚举Swift中的数组,并删除某些项目。我想知道这样做是否安全,如果不能,我应该如何实现这一目标。
目前,我会这样做:
for (index, aString: String) in enumerate(array) {
//Some of the strings...
array.removeAtIndex(index)
}
Answers:
您可以考虑以下filter
方法:
var theStrings = ["foo", "bar", "zxy"]
// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }
的参数filter
只是一个采用数组类型实例(在这种情况下String
)并返回的闭包Bool
。结果为true
保留元素时,否则将滤除元素。
filter
不会更新数组,它只会返回一个新数组
filter
方法合并为mutating
一个方法(因为我已经阅读了该mutating
关键字,而使像这样的函数可以更改self
)?
Array
标记为mutating
并类似于问题代码的扩展。无论如何,这可能并不总是一个优势。无论如何,每次删除对象时,阵列都可能会在内存中重新组织。因此,分配新数组然后使用filter函数的结果进行原子替换可能会更有效。取决于您的代码,编译器可以进行更多优化。
在Swift 3和Swift 4中,这将是:
根据约翰斯顿的答案,有数字:
var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
a.remove(at: i)
}
print(a)
使用字符串作为OP的问题:
var b = ["a", "b", "c", "d", "e", "f"]
for (i,str) in b.enumerated().reversed()
{
if str == "c"
{
b.remove(at: i)
}
}
print(b)
但是,现在在Swift 4.2或更高版本中, Apple在WWDC2018中推荐了一种更好,更快的方法:
var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)
这种新方法具有以下优点:
filter
。{$0 === Class.self}
怎么
当将某个索引处的元素从数组中删除时,所有后续元素的位置(和索引)都会改变,因为它们向后移了一个位置。
因此,最好的方法是以相反的顺序浏览数组-在这种情况下,我建议使用传统的for循环:
for var index = array.count - 1; index >= 0; --index {
if condition {
array.removeAtIndex(index)
}
}
但是我认为最好的方法是使用filter
@perlfly在其回答中描述的方法。
不,在枚举过程中更改数组并不安全,您的代码将崩溃。
如果只想删除几个对象,则可以使用该filter
功能。
filter
是安全的。这是我一个愚蠢的例子:var y = [1, 2, 3, 4, 5]; print(y); for (index, value) in y.enumerated() { y.remove(at: index) } print(y)
只需添加一下,如果您有多个数组,并且数组A的索引N中的每个元素都与数组B的索引N相关,那么您仍然可以使用反转枚举数组的方法(就像过去的答案一样)。但是请记住,在访问和删除其他数组的元素时,无需反转它们。
Like so, (one can copy and paste this on Playground)
var a = ["a", "b", "c", "d"]
var b = [1, 2, 3, 4]
var c = ["!", "@", "#", "$"]
// remove c, 3, #
for (index, ch) in a.enumerated().reversed() {
print("CH: \(ch). INDEX: \(index) | b: \(b[index]) | c: \(c[index])")
if ch == "c" {
a.remove(at: index)
b.remove(at: index)
c.remove(at: index)
}
}
print("-----")
print(a) // ["a", "b", "d"]
print(b) // [1, 2, 4]
print(c) // ["!", "@", "$"]