One qq about maps and chaining. Below code works perfectly fine
var raceResults = [["one","two","four"],["two","one","five","six"],["two","one","four","ten"],["one","two","four"]]
let numberedRaceResults = raceResults
.enumerated()
.flatMap { outterOffset, raceResult in
raceResult
.enumerated()
.map { innerOffset, element in "\(outterOffset).\(innerOffset). \(element)" }
}
for numberedResult in numberedRaceResults {
print(numberedResult)
}
But when I add two print statements in it , it stops working. Can someone-one please help me to understand
1.what's the deal with those print statements 2. If I replace flatmap with map, code below does not work. My understanding about flatmap is it just eliminates the nil values . Is there something on top of it that flatmap does comapred to map which is why I am not getting expected results when I replace flatmap with map ?
var raceResults = [["one","two","four"],["two","one","five","six"],["two","one","four","ten"],["one","two","four"]]
let numberedRaceResults = raceResults
.enumerated()
.flatMap { outterOffset, raceResult in
print(outterOffset)
print(raceResult)
raceResult
.enumerated()
.map { innerOffset, element in "\(outterOffset).\(innerOffset). \(element)" }
}
for numberedResult in numberedRaceResults {
print(numberedResult)
}
CodePudding user response:
When you write many lines inside the {}
of flatMap
function you need to tell it what should be the result and since print
returns () / void
,hence you get nothing , so you need to add a return
under the two prints
let numberedRaceResults = raceResults
.enumerated()
.flatMap { outterOffset, raceResult in
print(outterOffset)
print(raceResult)
return raceResult // here
.enumerated()
.map { innerOffset, element in "\(outterOffset).\(innerOffset). \(element)" }
}
for numberedResult in numberedRaceResults {
print(numberedResult)
}
CodePudding user response:
When the print
calls were absent, the body of the flatMap
closure was only a single expression, saying raceResult.enumerated().map { ... }
.
When the body of a closure is a single expression, the closure implicitly returns that expression. That is, the closure passed to flatMap
here actually means return raceResult.enumerated().map { ... }
.
When you add the print
calls, the closure is no longer a single expression, and so doesn't return the raceResult.enumerated().map { ... }
expression, and returns Void
instead. This actually makes it call another (deprecated) overload of flatMap
that "just eliminates the nil values", which we now call compactMap
.
The overload of flatMap
that is intended, allows you to map elements of an array to another sequence, and flattens it. For example, here we are mapping each race result to the array of raceResult.enumerated().map { ... }
. flatMap
will then flatten all these string arrays by joining them all together into a single array.
Anyway, you can fix the code by explicitly writing the return
.
let numberedRaceResults = raceResults
.enumerated()
.flatMap { (outterOffset, raceResult) -> [String] in
print(outterOffset)
print(raceResult)
return raceResult
.enumerated()
.map { innerOffset, element in "\(outterOffset).\(innerOffset). \(element)" }
}
Note that you also need to specify the return type of the closure now ([String]
), because Swift cannot infer the type of multi-statement closures very well :(