Grant Emerson

The Power of Reduce

The Power of Reduce — SwiftMoji Entry #3

In Swift, higher-order functions (functions which take another function as an argument) can drastically improve readability and shrink code size. In the following example, the reduce(into:_:) method on Array is used to combine elements into a Dictionary which maps each unique element to its corresponding count. More specifically, an Array of animal emojis is converted into a Dictionary by mapping each animal to its count. The initialResult of this operation is just an empty Dictionary ([:]). The animalCounts parameter in the closure is inferred to be of the type [String: Int] based on the surrounding context. Additionally, animalCounts is marked as inout because it is mutated in the closure. Next, the Dictionary of animal counts is converted into an Array of Strings describing the number of scientific groupings commonly formed. The initialResult of this reduce is an empty Array ([]). In each iteration of the reduce, a new key-value pair from the Dictionary of animalCounts is generated. The key is then used to look-up the correct AnimalGroup classification which provides the details necessary to calculate the number of groups present.

import Foundation

typealias AnimalGroup = (name: String, size: Int)

let animalGroups: [String: AnimalGroup] = [
    "🐬": ("pod", 12),
    "🐺": ("pack", 6),
    "🦒": ("tower", 10)
]

let animals = [
    "🐬", "🐬", "🐬", "🐬", "🐬", "🐬",
    "🐬", "🐬", "🐬", "🐬", "🐬", "🐬",
    "🐺", "🐺", "🐺", "🐺", "🐺", "🐺",
    "🐺", "🐺", "🐺", "🐺", "🐺", "🐺",
    "🦒", "🦒", "🦒", "🦒", "🦒", "🦒",
    "🦒", "🦒", "🦒", "🦒"
]

let groupedAnimals = animals
    .reduce(into: [:]) { animalCounts, animal in
        animalCounts[animal, default: 0] += 1
    }
    .reduce(into: []) { groups, animalCount in
        let animal = animalCount.key
        let amount = animalCount.value
        let groupSize = animalGroups[animal]!.size
        let groupName = animalGroups[animal]!.name
        let amountOfGroups = Int((Double(amount) / Double(groupSize)).rounded())
        groups.append("\(amountOfGroups) \(groupName)\(amountOfGroups > 1 ? "s" : "") of \(animal)")
    }

// ["2 packs of 🐺", "1 tower of 🦒", "1 pod of 🐬"]
Tagged with: