Let's try to sort things out. Array has a map() method
/// Returns an array containing the results of mapping the given closure
/// over the sequence's elements.
public func map<T>(_ transform: (Element) throws -> T) rethrows -> [T]
which creates a new array by transforming each element, and a
flatMap() method
/// Returns an array containing the non-`nil` results of calling the given
/// transformation with each element of this sequence.
public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
which is similar but ignores the elements which are mapped to nil
by the closure.
And there is another flatMap() method
/// Returns an array containing the concatenated results of calling the
/// given transformation with each element of this sequence.
public func flatMap<SegmentOfResult : Sequence>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element]
which transforms each element to a sequence and concatenates the
results.
Your code calls the second flatMap() method to flatten the
array to one dimension, and then the first flatMap() method to
convert the strings to numbers.
The first candidate for transforming arrays (or sequences in general) is map(), and that
works for nested arrays as well:
let strings = [["1.0", "2.0"],["3.0", "4.0"]]
let doubles = strings.map { $0.map { Double($0) }}
print(doubles) // [[Optional(1.0), Optional(2.0)], [Optional(3.0), Optional(4.0)]]
The result is a nested array of optionals because the conversion
to a floating point value can fail. How to fix that?
Forcefully unwrap (usually not recommended):
let strings = [["1.0", "2.0"],["3.0", "4.0"]]
let doubles = strings.map { $0.map { Double($0)! }}
print(doubles) // [[1.0, 2.0], [3.0, 4.0]]
That is fine if you have fixed data and can guarantee that
each string is a valid floating point value. If not, the program
will crash:
let strings = [["1.0", "2.0"],["3.0", "wot?"]]
let doubles = strings.map { $0.map { Double($0)! }}
// fatal error: unexpectedly found nil while unwrapping an Optional value
Provide a default value:
let strings = [["1.0", "2.0"],["3.0", "wot?"]]
let doubles = strings.map { $0.map { Double($0) ?? 0.0 }}
print(doubles) // [[1.0, 2.0], [3.0, 0.0]]
Here the invalid string is mapped to 0.0, so that the "shape"
of the array is preserved. But 0.0 is a "magic number" now,
and we cannot see from the result if it comes from a valid
or an invalid string.
Ignore invalid strings. And now flatMap() comes into play
(the first version):
let strings = [["1.0", "2.0"],["3.0", "wot?"]]
let doubles = strings.map { $0.flatMap { Double($0) }}
print(doubles) // [[1.0, 2.0], [3.0]]
The inner flatMap() returns an array of the non-nil
Double($0) values, i.e. all invalid strings are ignored.
Advantage: The code cannot crash due to invalid input,
and no "magic numbers" are used.
Possible disadvantage: The array shape is not preserved.
So pick your choice!
flatMap()methods.