Home > Blockchain >  Issues with swift map chaining
Issues with swift map chaining

Time:09-06

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 :(

  • Related