Question re .map and closures - Using Swift - Swift Forums
When to use map vs. for loop?
Iterating array of array in swift using map - Stack Overflow
How to center map on user location when app is opened?
Videos
Been playing around with map, flatMap, filter, reduce, forEach, etc. and love the syntax of them all. The first thought I had after discovering map was "Why would I ever need a for loop / forEach if I can just use map?"
Did some google searches and found a few discussions but they were either lacking in info or too low level for me to understand. I'm basically interested in performance and following best practices.
If anyone here knows the answer and could ELI5 I would really appreciate it. I want to start making use of all of these new functions but don't want to go overboard either.
Thanks and I appreciate the help.
Let's start with a single array, like:
Copylet raceResult = ["one", "two", "four"]
If we want to combine each element with an offset counting from 0, we can use Array.enumerated(), along with map.
Copylet numberedRaceResult = raceResult
.enumerated()
.map { offset, element in "\(offset). \(element)" }
for numberedResult in numberedRaceResult {
print(numberedResult)
}
// Prints:
// 0. one
// 1. two
// 2. four
You can see that I didn't call print inside the closure passed to map. You can do this, but it kind of defeats the purpose of map (which is to create an equal-sized output array from the transformed elements of the input array), because the result would be unused. In that case, it makes more sense to just use a for loop or a call to forEach, like @Sh_Khan showed.
To handle a nested array, it's much the same. We can use the same logic as for one array, but apply it to each sub-array.
Copylet 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)
}
// Prints:
// 0.0. one
// 0.1. two
// 0.2. four
// 1.0. two
// 1.1. one
// 1.2. five
// 1.3. six
// 2.0. two
// 2.1. one
// 2.2. four
// 2.3. ten
// 3.0. one
// 3.1. two
// 3.2. four
You'll notice that I used flatMap on the outter array, instead of a simple map. You can change it back and forth and compare the result. In short, flatMap gives you a single flat array of string results, rather than an array of sub-arrays of strings.
Map is used to convert one bunch of type T into things of some other type, X. Like map these Ints to String?s. You should not use map for side-effects, like printing the values, or updating a database etc. It should be a pure function that takes an input and returns an output. "Map these A's into B's". Pure meaning the value of the function only depends on the input, nothing else like the current state of the world, and doesn't change the world either (like printing to the console), so for example, map these int's by the function that adds 2 to them.
In your example:
Copyvar raceResults = [["one","two","four"],["two","one","five","six"],["two","one","four","ten"],["one","two","four"]]
You have an array of "arrays of strings".
You can map that to an array of so long as you have a function that takes "array of string" and turns that into "something else"
Here you map it with the Identity function, the function that just returns its input, which is going to take an array of strings as input and return the exact same array of strings as output:
Copy raceResults.map {
return $0 // Returns first array
}
This does nothing, and the result is the exact same thing as raceResults.
If you want to iterate over all these elements then the function flatMap is handy:
CopyraceResults.flatMap { $0 }.forEach { print($0) }
flatMap is flatten, then map. Flattening an array of arrays is to return an array with all the things 'flattened' one level, so [[1, 2, 3], [4, 5, 6]] -> [1, 2, 3, 4, 5, 6], but the definition of what to flatten means depends on the type of container, for example flatMap on Optional means something else to flatMap on Array.