bibscy
bibscy

Reputation: 2718

Use map() method in swift 2.1

I have this code from Apple library and I am trying to understand how map() method works.

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]


let strings = numbers.map {
  (var number) -> String in
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}

In the specification it is written that the closure calculates the
last digit of 'number 'using the % reminder operator and this digit (which is var number) is used to
look up an appropriate string in 'digitNames'.

Why does it calculate the last digit of 'number' and not the first one? How is the 'output' string built?

My understanding is that First iteration: while number = 1, output = ["one"] and number / 10 = 0 Because digit 1 is a valid Key in 'digitNames' dictionary, and 'number' is equal to 0
"One" will be returned by the closure. Now, the map() method is called on the 'numbers' Array and it will add "One" to 'output'

Does the map() method only add the return of the closure to the 'output'
Array once 'number' = 0 or does it check if output value is contained in 'numbers' before adding the return of the closure to the 'output'?

My understanding, even though it must not be right is that: for number = 1...9 number / 10 is equal 0, therefore the while loop condition is satisfied
number > 0 and the closure will return the 'output' as number + output and
build "OneTwoThree". So for

number = 1, output = [One]
number = 2, output = [OneTwo] 

and so forth.

Could you describe step by step the flow of the code and how it works?

Upvotes: 1

Views: 413

Answers (2)

matt
matt

Reputation: 536047

The map method cycles through an array (or a thing like an array) and, for each element of the array, returns a new value. Those returned values form a new array that is the result of the map method. So each element of the original array maps to an element of the new array.

The way the map method knows what to do with each element of the original array is that you supply a function (often, though not necessarily, an anonymous function). The function processes an element of the original array and returns a value to give the mapped value for the corresponding element of the new array.

So, playing around in a Playground, you'll see that [1,2,3,4].map{$0*2} is [2,4,6,8]. Why? Because we cycled through the array [1,2,3,4] and our supplied function, for each element, returned that element multiplied by 2.

Perhaps it would help if I wrote that more verbosely like this:

[1,2,3,4].map {
    anElement in
    return anElement * 2
}

Or even more verbosely as:

func multiplyBy2(anElement:Int) -> Int {
    return anElement * 2
}
[1,2,3,4].map (multiplyBy2)

You can see that this is the case also for the Apple example. Again, it may help if I express the map function as an actual function and try it out separately before I use it as a map function. So:

let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
func wordify(number:Int) -> String {
    var output = ""
    var number = number
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}

Okay, let's try it on a few numbers

wordify(16) // "OneSix"
wordify(58) // "FiveEight"
wordify(510) // "FiveOneZero"

Okay, let's use it in map:

let numbers = [16, 58, 510]
numbers.map(wordify) // ["OneSix", "FiveEight", "FiveOneZero"]

The result is exactly the same as if we'd applied the function to each element of the array separately, combined into an array — just what we expect.

Upvotes: 1

Blake Lockley
Blake Lockley

Reputation: 2961

Map is a higher order function that when called on an array will produce a new array (possibly of a different type) where all the elements are the result of preforming a certain operation on each element of the original array. So we will take a look at its type signature (note this is completely over simplified so we can focus on map):

class [T] {
  func map<T, U>(T -> U) -> [U]
}

Note: its important you understand the concept of generic types in swift to understand this example.

So map is a method that operates on the array of of type [T] (which is just syntactic sugar for Array<T>). We can see that map takes a closure of type T -> U This means given one type it can return another e.g. Int -> String or Double -> Double.

From the type signature we can see that map returns an array of type [U]. So it gets each element from the original array and feeds it to the closure which return a result of type U which is then adds to the result.

Upvotes: 1

Related Questions