How can I remove all nil elements in a Swift array?
Basic way doesn't work.
for index in 0 ..< list.count {
if list[index] == nil {
list.removeAtIndex(index) //this will cause array index out of range
}
}
Solution 1:
The problem with your code is that 0 ..< list.count
is executed once at the beginning of the loop, when list
still has all of its elements. Each time you remove one element, list.count
is decremented, but the iteration range is not modified. You end up reading too far.
In Swift 4.1 and above, you can use compactMap
to discard the nil
elements of a sequence. compactMap
returns an array of non-optional values.
let list: [Foo?] = ...
let nonNilElements = list.compactMap { $0 }
If you still want an array of optionals, you can use filter
to remove nil
elements:
list = list.filter { $0 != nil }
Solution 2:
In Swift 2.0 you can use flatMap:
list.flatMap { $0 }
Solution 3:
Now in swift 4.2 you can use
list.compactMap{ $0 }
list.flatMap{ $0 }
is already deprecated.
Solution 4:
A much elegant solution would be to use compacted()
defined in the Algorithms package made by Apple itself.
import Algorithms
let array = [10, nil, 20, nil, 30]
print(array.compacted()) // prints [10, 20, 30]
Benefits
- Concise
- Filters out nil items lazily
More info https://github.com/apple/swift-algorithms/blob/main/Guides/Compacted.md