Assume we have an array of optionals defined:
var arrayOfOptionals: [String?] = [\"Seems\", \"like\", \"an\", nil, \"of\", \"optionals\"]
I
This solution will get you a new array with all values unwrapped and all nil's filtered away.
Swift 4.1:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.compactMap { $0 }
Swift 2.0:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.flatMap { $0 }
Swift 1.0:
let arrayOfOptionals: [String?] = ["Seems", "like", "an", nil, "of", "optionals"]
let arrayWithNoOptionals = arrayOfOptionals.filter { $0 != nil }.map { $0! }
I took @Cenny's answer and decided to make an operator out of it:
prefix operator <!> {}
prefix func <!> <T>(array: [T?]) -> [T] {
return array.filter{ $0 != nil }.map{ $0! }
}
I'm using it to parse an array of JSON objects and filter the ones that failed:
static func parse(j: JSONArray) -> [Agency]? {
return <!>j.map { self.parse($0) }
}
Update for Swift 2+:
Use flatMap
operator and it'll only return non-nil objects
Swift 4
Easy to read and safe approach to filter nils of any sequence
protocol OptionalProtocol {
associatedtype Wrapped
var optional: Wrapped? { get }
}
extension Optional: OptionalProtocol {
var optional: Wrapped? {
return self
}
}
extension Sequence where Element: OptionalProtocol {
var removingOptionals: [Element.Wrapped] {
return self.compactMap { $0.optional }
}
}
Usage
let array: [Int?] = [1, 2, nil, 3, 4, nil]
print(array.removingOptionals) // prints [1, 2, 3, 4], has type [Int]
How about:
import Foundation
var test: [String!] = ["this","is","a",nil,"test"]
for string in test {
if string != nil {
print(string)
}
}
Output is thisisatest
.
In your case use [String!]
, if I understood you correctly.
Since it is an array of optionals, it is possible some of the entries are nil
. Instead of force unwrapping with !
, use the nil coalescing operator to turns nil
s into empty strings.
let arrayOfOptionals: [String?] = ["This", "array", nil, "has", "some", "nils", nil]
let array:[String] = arrayOfOptionals.map{ $0 ?? "" }
// array is now ["This", "array", "", "has", "some", "nils", ""]
The more interesting, how to unwrap an optional array of optional values. It is important to deal when we are working with JSON, because JSON can potentially contain null
value for an array of something.
Example:
{ "list": null }
// or
{ "list": [null, "hello"] }
To fill a Swift struct we may have a model:
struct MyStruct: Codable {
var list: [String?]?
}
And to avoid working with String??
as a first item we could:
var myStruct = try! JSONDecoder.init().decode(MyStruct.self, from: json.data(using: .utf8)!)
let firstItem: String? = s1.list?.compactMap { $0 }.first
With compactMap { $0 }
we can avoid
let i2: String?? = s1.list?.first
compactMap { $0 }
is an equivalent of filter { $0 != nil }. map { $0! }