Map on collections in Swift

Swift provides a number of map methods to transform elements in Swift collections and return the transformed data in a new Array. The transform is supplied in a trailing closure to the map function. This article looks at Map, FlatMap and CompactMap on collections in Swift as well as MapValues in Dictionary.



Map on Array of Numbers and Strings

map is an instance method applied to a collection element such as an Array that applies some function/operation to each element in the collection and returns an array with the transformed elements. This operation to perform is passed in a trailing closure and can be any valid operation on the elements in the original collection. This example returns an array of the squares of the original numbers. Numbers can be converted to text or used in calculations and text case can be manipulated. The original collection remains unmodified by the map function.

 1let nums = [1, 2, 3, 4, 5]
 2print(nums)
 3print()
 4
 5let squared = nums.map { $0 * $0 }
 6print(squared)
 7print()
 8
 9let stringNums = nums.map { "\($0)" }
10print(stringNums)
11print()
12
13let numSquared = nums.map { "\($0) squared is \($0 * $0)" }
14print(numSquared)
15print()
16
17let strings = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
18print(strings)
19let upperStrings = strings.map { $0.uppercased() }
20print(upperStrings)

Use Map to transform an array of numbers to another array with the specified closure
Use Map to transform an array of numbers to another array with the specified closure



Map on a Set

Map can also be applied to Set, similar to Array. It returns an Array rather than a Set with elements created from applying the transform to the Set elements.

 1let numSet = Set([1,2,3,2,3,4,5,6,-3,4,])
 2print("numSet = \(numSet)")
 3print()
 4
 5let squaredSet = numSet.map { $0 * $0 }
 6print(squaredSet)
 7print("Type returned from map method on Set is \(type(of: squaredSet))")
 8print()
 9
10let sortedSquares = numSet.map { $0 * $0 }.sorted()
11print(sortedSquares)
12print()

Use Map to transform a Set of numbers returns an Array
Use Map to transform a Set of numbers returns an Array



Map and mapValues on Dictionary

Map on a Dictionary will allow the transform to work on the elements in the dictionary. Since the elements in the dictionary consist of a key/value pair, simply applying map to the dictionary will require accessing the key or value within the transform. The Map function will return an Array containing the transformed values.

Swift provides mapValues that will return a new dictionary with the same keys as the original dictionary and the values transformed by the closure. The code shows that map returns an array of squared values and mapValues returns a new dictionary with the values squared for each key.

 1/******************************************************/
 2/*   Dictionary                                       */ 
 3/*                                                    */ 
 4
 5let dict = ["red": 1, 
 6            "orange": 2, 
 7            "yellow": 3,
 8            "green": 4,
 9            "blue": 5,
10            "indigo": 6,
11            "violet": 7]
12
13print(dict)
14print()
15
16let squareArray = dict.map { $0.value * $0.value }
17print(squareArray)
18print("Type returned from map method on Dictionary is \(type(of: squareArray))")
19print()
20
21let squareDict = dict.mapValues { $0 * $0 }
22print(squareDict)
23print("Type returned from mapValues method on Dictionary is \(type(of: squareDict))")
24print()

Use Map to transform a Dictionary returns an Array
Use Map to transform a Dictionary returns an Array



FlatMap

flatMap is used when the transform on the elements in the original collection results in a sequence for each element or when the original collection is a sequence of sequences. FlatMap can simply be used to concatenate a list of lists into a single list.

 1let nums = [1, 2, 3, 4]
 2print(nums)
 3print()
 4
 5let expanded = nums.map { [$0, $0 * $0, $0 * $0 * $0] }
 6print("expanded:\n\(expanded)")
 7expanded.map { print($0) }
 8print()
 9
10let expanded2 = nums.flatMap { [$0, $0 * $0, $0 * $0 * $0] }
11print("expanded2:\n\(expanded2)")

In an Array of Arrays, FlatMap is used to convert to a single Array and then Map is used to transform the elements resulting in a new single Array with all the elements transformed.

 1let lists = [[1, 5, 3], [4, 1], [9, 2, 6],[5, 7, 2, 3]]
 2print("\n\n\n\nList of lists")
 3lists.map { print($0) }
 4print()
 5
 6let flatList = lists.flatMap { $0 }
 7print("flatList:\n\(flatList)")
 8print()
 9
10let flatSquares = lists
11    .flatMap { $0 }
12    .map { $0 * $0 }
13print("flatSquares:\n\(flatSquares)")

Use FlatMap to collapse an array or arrays into a single Array
Use FlatMap to collapse an array or arrays into a single Array



CompactMap

compactMap is used to return an array of non-nil values when the transform can result in nil values for elements in the sequence. Useful when the transform produces an array of optional values. This code finds words starting with uppercase letters in the string. The map function will return the option values with some of the elements being nil, whereas the compactMap just returns the non-nil values and unwraps the optionals.

 1import Foundation
 2
 3let text = "The Rain in Spain falls mainly in the Plain"
 4let words = text.components(separatedBy: .whitespacesAndNewlines)
 5print(words)
 6print()
 7
 8let cap1 = words.map { $0.first?.isUppercase ?? false ? $0 : nil }
 9print(cap1)
10print()
11
12let cap2 = words.compactMap { $0.first?.isUppercase ?? false ? $0 : nil }
13print(cap2)

Use CompactMap to eliminate nil values from the transformed Array
Use CompactMap to eliminate nil values from the transformed Array




Conclusion

There is frequently the need to transform one collection into another and while this can be done with a For or ForEach loop, Swift provides Map functions tailored to this requirement. The map function take a trailing closure with code to apply to each element in the collection and return the transformed array. All map functions return an Array regardless of the type of the collection to which the map is applied. The Dictionary type also provides mapValues that returns a dictionary with the original keys and the values transformed. FlatMap function is used to collapse (Flatten) a sequence of sequences into a single sequence, while CompactMap function is used to eliminate nil values from the transformed collection.