繁体   English   中英

在 Swift 枚举期间从数组中删除?

[英]Removing from array during enumeration in Swift?

我想枚举Swift中的一个数组,并删除某些项目。 我想知道这样做是否安全,如果不安全,我应该如何实现这一目标。

目前,我会这样做:

for (index, aString: String) in enumerate(array) {
    //Some of the strings...
    array.removeAtIndex(index)
}

在 Swift 2 中,这很容易使用enumeratereverse

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerate().reverse() {
    a.removeAtIndex(i)
}
print(a)

您可能会考虑filter方式:

var theStrings = ["foo", "bar", "zxy"]

// Filter only strings that begins with "b"
theStrings = theStrings.filter { $0.hasPrefix("b") }

filter的参数只是一个闭包,它接受一个数组类型实例(在本例中为String )并返回一个Bool 当结果为true它保留该元素,否则该元素被过滤掉。

Swift 3 和 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)

这种新方式有几个优点:

  1. 它比使用filter实现更快。
  2. 它不需要反转数组。
  3. 它就地删除项目,因此它更新原始数组而不是分配和返回新数组。

当某个索引处的元素从数组中移除时,所有后续元素的位置(和索引)都将发生变化,因为它们向后移动了一个位置。

所以最好的方法是以相反的顺序导航数组 - 在这种情况下,我建议使用传统的 for 循环:

for var index = array.count - 1; index >= 0; --index {
    if condition {
        array.removeAtIndex(index)
    }
}

然而,在我看来,最好的方法是使用filter方法,正如@perlfly 在他的回答中所描述的那样。

不,在枚举期间改变数组是不安全的,你的代码会崩溃。

如果您只想删除几个对象,您可以使用filter功能。

要么创建一个可变数组来存储要删除的项目,然后在枚举之后,从原始项目中删除这些项目。 或者,创建数组的副本(不可变),枚举它并在枚举时从原始对象中删除对象(而不是通过索引)。

传统的 for 循环可以用一个简单的 while 循环代替,如果您还需要在删除之前对每个元素执行一些其他操作,这将非常有用。

var index = array.count-1
while index >= 0 {

     let element = array[index]
     //any operations on element
     array.remove(at: index)

     index -= 1
}

我建议在枚举期间将元素设置为 nil,并在完成后使用数组 filter() 方法删除所有空元素。

补充一点,如果您有多个数组,并且数组 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) // ["!", "@", "$"]

你可以这样做Swift 5

arr?.removeAll(where: {$0.id as! Int == id})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM