preface

In Swift, it is very convenient to use map, filter, and reduce on collection types such as Array and Dictionary. If you have no experience with functional languages, your first instinct when dealing with collection types is probably to use for-loop. This article aims to help you quickly understand the basic concepts of Map, filter and Reduce in SWIFT and skillfully use them to improve the efficiency of SWIFT development.

Map

The convenience of using a Map is that it iterates over a collection object and can apply the same operations to each element of the object. The map function returns an array containing the new values generated after the same operation is performed on each element of the collection object.

// forcycleletValues = [2.0, 4.0, 5.0, 7.0] var squares: []for value inValues {squares.append(value*value)} // Map mechanismletValues = [2.0, 4.0, 5.0, 7.0]let squares = values.map { $0 * $0 }
// [4.0, 16.0, 25.0, 49.0]
Copy the code

The for loop allows us to use more, but the code is not elegant, we have to declare a square and it is a mutable array (which will probably change when we use it below). Using map, squares are defined directly as lets, or immutable groups, and we don’t even have to specify the type of squares because Swift can infer the types.

The map function takes only one closure (which is also a function) as an argument. When the map traverses the collection object once, the closure argument is executed once. This closure takes the element in the collection object as an argument and returns a new value. Finally, the map function returns an array containing the new values.

The above code is a shorthand form. Now let’s restore the implementation of the map function to make it easier to understand what happens to the map function.

letValues = [2.0, 4.0, 5.0, 7.0]let squares2 = values.map({ (value: Double) -> Double in 
  return value * value
})
Copy the code

The tail closure has only one argument: (value: Double) and return Double, depending on the type of the argument value, so Swift can infer the type of the return value. Also, since the map function has only one closure as an argument, we don’t need the () parentheses around the argument (value: Double), or even the return keyword. The map function argument can be abbreviated in one line, as follows:

let squares2 = values.map { value in 
  value * value
}
Copy the code

The in keyword is used to separate the closure arguments from the function body. If you prefer, you can further abbreviate the numbered arguments using the following code:

let squares = values.map { $0 * $0 }
Copy the code

Map function returns an array containing the element type will not be limited to the original type of the elements in an array, said popular point is the sentence after the map function, a new array element type and the original array element type, not necessarily must be different, not much any of that crap, there is a demo, the integer array element mapping as a string type, the following code,

letScores =,28,124 [0]let words = scores.map { NSNumberFormatter.localizedStringFromNumber($0, numberStyle: .SpellOutStyle) 
}
// ["zero"."twenty-eight"."one hundred twenty-four"]
Copy the code

The map function can be used with any collection type, such as dictionaries, arrays, and sets. In the following example, a map is used with dictionaries and sets. Note that the map always returns an Array. As shown in the following code,

// Convert kilometers to mileslet milesToPoint = ["point1": 120.0."point2": 50.0."point3": 70.0]let kmToPoint = milesToPoint.map { name,miles inMiles * 1.6093}Copy the code

In the example above, to traverse the Dictionary, we use the map operation on it. The map function takes a String and a Double. The String and Double variables are made up of keys: values from each element in the Dictionary.

TIPS: If you don’t know what type of parameters a collection object should use when using a map, you can use Xcode auto-completion to check the type of parameters, as shown below.

For sets, use map:

letLengthInMeters: Set = [4.0, 6.2, 8.9]let lengthInFeet = lengthInMeters.map {meters inMeters * 3.2808}Copy the code

Filter

Filter, just as its name implies, is the meaning of filtration, screening, for a collection objects, the function of the Filter function is through the collection, and then will meet certain conditions of elements in the collection of new arrays, and returns the new array, the Filter function is to choose qualified element in the collection, Filter out the element is not in conformity with the conditions, As shown in the picture below,

The filter function takes a single closure that specifies the filter criteria. The closure takes an element from the collection object as an argument and must return a Bool indicating whether the element should be included in the new array and returns. The following example uses the filter operation on an array to return all the even numbers in the array

let digits = [1, 4, 5, 10, 15]
let even = digits.filter { (number) -> Bool in return
   number % 2 == 0
}
// [4, 10]
Copy the code

You can also abbreviate it like this:

let digits = [1, 4, 10, 15]
let even = digits.filter { $0% 2 == 0} // [4, 10]Copy the code

Reduce

The reduce function can combine all the elements in a collection, generate a new value and return it, as shown below:

The Reduce function accepts two arguments, an initial value and a combine closure. For example, to add the elements of an array to an initial value of 10, the Reduce function can be used, as shown in the following code:

letItems = [2.0, 4.0, 5.0, 7.0]letTotal = items.reduce(10, combine: +) // 28.0Copy the code

Similarly, this applies to concatenating strings in an array with +, as follows,

let codes = ["abc"."def"."ghi"]
let text = codes.reduce("", combine: +)
// "abcdefghi"
Copy the code

The combine parameter of Reduce function is a closure, so we can also use the syntactic form of tail closure to write Reduce function, as shown in the following code,

let name = ["alan"."brian"."charlie"]
let scv = name.reduce("= = =") { text, name in 
  "\(text), \(name)"} / /"==, alan, brian, charlie"
Copy the code

Name is an element in the array, and text is equivalent to the value generated after name is joined together in each operation. Here, the initial value of text is “===”, and after the execution of reduce function, text is the final returned value, that is, “==, Alan, Brian, Charlie “.

FlatMap

FlatMap is a mash-up of multiple collections into a single collection

let collections = [[5, 2, 7], [4, 8], [9, 1, 3]]
let flat = collections.flatMap { $0 }
// [5, 2, 7, 4, 8, 9, 1, 3]
Copy the code

Even more, flatMap recognizes optional values, which will remove nil elements from the collection, as shown in the code below

let people: [String?] = ["Tom", nil, "Peter", nil, "Harry"]
let valid = people.flatMap { $0} / / /"Tom"."Peter"."Harry"]
Copy the code

Take a look at the combination of filter and flatMap. First flatten multiple word groups in an array into an array, and then filter out the even numbers in the array using filter, as shown in the code below

let collections = [[5, 2, 7], [4, 8], [9, 1, 3]]
let onlyEven = collections.flatMap { intArray in 
  intArray.filter { $0 % 2 == 0 }
 // result -- [2, 4, 8]
}
Copy the code

Notice here. The flatMap traverses the subarrays of integer numbers in the Collections array, so the parameter to the flatMap is a closure that takes an array of integer numbers, that is, [Int]. This code could also have been written using the more concise and esoteric closure syntax, as shown in the code below

let collections = [[5, 2, 7], [4, 8], [9, 1, 3]]
let onlyEven = collections.flatMap { $0.filter { $0 % 2 == 0 }}
// result -- [2, 4, 8]
Copy the code

Look at an example, the flatMap and map combination, for a son contain multiple integer array element within an array of all integer square value calculation, and calculates the square values into the new array of return, here we provide two ways to z to implement such a demand, one kind is concise closure type of grammar, the other is a complete normative grammar, See the code below

letcollections = [[5, 2, 7], [4, 8], [9, 1, 3]] // 1. Concise waylet allSquared = collections.flatMap { $0.map { $0 * $0}} // 2let allSquared2 = collections.flatMap { intArray in 
  intArray.map { $0 * $0 }
}
// result -- [25, 4, 49, 16, 64, 81, 1, 9]
Copy the code

For the final example of flatMap, use flatMap and Reduce to calculate the sum (sum) of all elements in all subarrays of integers in an array, again using the closure shorthand syntax and full specification, as shown in the following code

let collections = [[5, 2, 7], [4, 8], [9, 1, 3]]
let sums = collections.flatMap { $0.reduce(0, combine:+) }
let sums2 = collections.flatMap { intArray in 
  intArray.reduce(0, combine:+)
}
Copy the code

Chaining syntax

We can use Swift’s map, filter, reduce and flatMap through chain syntax. For example, to calculate the sum of numbers greater than or equal to 7 in the set, filter can be used first, and then sum using reduce, as shown in the following code

let marks = [4, 5, 8, 2, 9, 7]
let totalPass = marks.filter { $0 >= 7}.reduce(0, combine: +)
// result - 24
Copy the code

For example, if the square value of an array is even, you can calculate all the square values through map and filter out the even values, as shown in the following code

let numbers = [20, 17, 35, 4, 12]
let evenSquares = numbers.map { $0 * $0 }.filter { $0 % 2 == 0 }
// result -- 400, 16, 144
Copy the code

conclusion

Later in swift coding, when you realize that you are traversing a collection object, you should consider using map, filter, or Reduce functions instead.

The following features of Map, filter, and Reduce are summarized.

  • The map returns a result set containing all the elements that have been transformed into new elements by performing the same transformation on each element in the source array.
  • Filter returns a result set containing every element in the source array that matches the filter criteria.
  • Reduce returns a value that is generated by calling the same operation in the closure for the initial value and for each element in the collection.

Reference links useyourloaf.com/blog/swift-…