Reduce

Introduction

Welcome to Lesson 3 of Functional Programming. I don’t think I have to talk too much. Let’s get into the lesson right away.

Problem

Combine all into one

Imperative/Non-Functional

Let’s try to add up numbers in an array.

  1. var numberOne = Int()
  2. for number in Array(1...10) {
  3. numberOne += number
  4. }
  5. numberOne // 55

Let’s try to subtract all numbers in an array.

  1. var numberTwo = Int()
  2. for number in Array(1...10) {
  3. numberTwo -= number
  4. }
  5. numberTwo // -55

Again, there must be a better way. You know the drill.

Declarative/Functional Programming

  1. let added = Array(1...10).reduce(0) { $0 + $1 } // 55
  2. let subtracted = Array(1...10).reduce(0) { $0 - $1 } // -55

You will discover how the reduce function works behind the scene by the end of this lesson. Let’s get started.

  1. func myReduce(_ seed: Int, numbers: [Int], operation: (Int, Int) -> Int) {
  2. var current = seed
  3. for number in numbers {
  4. current = operation(current, number)
  5. }
  6. }

seed represents the initial value you wish to start off with.

  1. myReduce(0, numbers: Array(1...10)) { $0 + $1 }

Ex) Finding the Max

  1. let maxNumber = Array(1...10).reduce(0) { (total, number) in max(total, number) }
  2. let bigNumber = Array(1...10).reduce(0) { max($0, $1) }

So far, myReduce has not returned any. Let’s create a function that returns the final value in Int.

  1. func reduce(_ seed: Int, numbers: [Int], operation: (Int, Int) -> Int) -> Int {
  2. var current = seed
  3. for number in numbers {
  4. current = operation(current, number)
  5. }
  6. return current
  7. }
  8. reduce(0, numbers: Array(1...10)) { $0 + $1 }

Generic Reduce

Again, creating a generic function is just a required for the sake of time and efficiency.

  1. extension Array {
  2. func myReduce<U>(_ seed: U, operation:(U, U) -> U) -> U {
  3. var current = seed
  4. for item in self {
  5. current = operation(current, item as! U)
  6. }
  7. return current
  8. }
  9. }

Currently, there is a force casting using as! U. It occurs since the type of U is not defined until you use the myReduce function.

  1. let names = ["Bob", "Bobby", "Lee"]
  2. let description = names.myReduce("Names:") { "\($0) " + $1 }
  3. print(description) // "Names: Bob Bobby Lee"

Not only that, you may “chain” multiple functions.

  1. let lowerNames = names.map { $0.lowercased() }.myReduce("Names:") { "\($0) " + $1 }
  2. print(lowerNames) // "Names: bob bobby lee"

The Purest Form

  1. //: The Purest Form
  2. extension Array {
  3. func reduce(_ seed: Element, operation:(Element, Element) -> Element) -> Element {
  4. var current = seed
  5. for item in self {
  6. current = operation(current, item)
  7. }
  8. return current
  9. }
  10. }
  11. let hello = ["Bob", "Bobby", "Lee"].reduce("Names:") { "\($0) " + $1 }

Source Code

6004_reduce.playground

Conclusion

I hope by now you are truly seeing the power of functions. Well, a functional paradigm is not specifically tied to iOS development. In fact, you’ve learned how to apply and utilize closure and generics in web development, server development, Android development, and other platforms. This course isn’t just about learning Swift. It is about to learn how to code with beauty and class. Let’s get to the final function of this chapter.