Removing from array during enumeration in Swift?

2019-01-17 05:26发布

I want to enumerate through an array in Swift, and remove certain items. I'm wondering if this is safe to do, and if not, how I'm supposed to achieve this.

Currently, I'd be doing this:

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

7条回答
趁早两清
2楼-- · 2019-01-17 05:45

I recommend to set elements to nil during enumeration, and after completing remove all empty elements using arrays filter() method.

查看更多
贪生不怕死
3楼-- · 2019-01-17 05:51

No it's not safe to mutate arrays during enumaration, your code will crash.

If you want to delete only a few objects you can use the filter function.

查看更多
时光不老,我们不散
4楼-- · 2019-01-17 05:52

In Swift 2 this is quite easy using enumerate and reverse.

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

See my swiftstub here: http://swiftstub.com/944024718/?v=beta

查看更多
闹够了就滚
5楼-- · 2019-01-17 05:55

You might consider filter way:

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

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

The parameter of filter is just a closure that takes an array type instance (in this case String) and returns a Bool. When the result is true it keeps the element, otherwise the element is filtered out.

查看更多
Melony?
6楼-- · 2019-01-17 05:56

In Swift 3 and 4, this would be:

With numbers, according to Johnston's answer:

var a = [1,2,3,4,5,6]
for (i,num) in a.enumerated().reversed() {
   a.remove(at: i)
}
print(a)

With strings as the OP's question:

var b = ["a", "b", "c", "d", "e", "f"]

for (i,str) in b.enumerated().reversed()
{
    if str == "c"
    {
        b.remove(at: i)
    }
}
print(b)

However, now in Swift 4.2, there is even a better, faster way that was recommended by Apple in WWDC2018:

var c = ["a", "b", "c", "d", "e", "f"]
c.removeAll(where: {$0 == "c"})
print(c)

This new way has several advantages:

  1. It is faster than implementations with filter.
  2. It does away with the need of reversing arrays.
  3. It removes items in-place, and thus it updates the original array instead of allocating and returning a new array.
查看更多
爷的心禁止访问
7楼-- · 2019-01-17 06:03

When an element at a certain index is removed from an array, all subsequent elements will have their position (and index) changed, because they shift back by one position.

So the best way is to navigate the array in reverse order - and in this case I suggest using a traditional for loop:

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

However in my opinion the best approach is by using the filter method, as described by @perlfly in his answer.

查看更多
登录 后发表回答