🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of mannylopez

mannylopez's solution

to Accumulate in the Swift Track

Published at Apr 01 2021 · 1 comment
Instructions
Test suite
Solution

Implement the accumulate operation, which, given a collection and an operation to perform on each element of the collection, returns a new collection containing the result of applying that operation to each element of the input collection.

Given the collection of numbers:

  • 1, 2, 3, 4, 5

And the operation:

  • square a number (x => x * x)

Your code should be able to produce the collection of squares:

  • 1, 4, 9, 16, 25

Check out the test suite to see the expected function signature.

Restrictions

Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! Solve this one yourself using other basic tools instead.

Setup

Go through the project setup instructions for Xcode using Swift:

http://exercism.io/languages/swift
http://exercism.io/languages/swift/tests

Notably from the source directory:

swift test runs tests
swift package generate-xcodeproj creates an Xcode project

Source

Conversation with James Edward Gray II https://twitter.com/jeg2

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

AccumulateTests.swift

import XCTest
@testable import Accumulate

private extension String {
    var length: Int { return self.count }

    func reverse() -> String {
        var result: String = ""
        for char in self {
            result = "\(char)\(result)"
        }
        return result
    }
}

private extension XCTest {
    func XCTAssertEqualMultiArray(_ aArray1: [[String]], _ aArray2: [[String]]) {
        XCTAssertEqual(Array(aArray1.joined()), Array(aArray2.joined()))
    }
}

class AccumulateTests: XCTestCase {
    func testEmptyAccumulation() {
        let input = [Int]()
        func square(_ input: Int) -> Int {
            return input * input
        }
        let result = input.accumulate(square)

        XCTAssertTrue(result.isEmpty)
    }

    func testAccumulateSquares() {
        let input = [1, 2, 3, 4]
        let expected = [1, 4, 9, 16]
        func square(_ input: Int) -> Int {
            return input * input
        }
        let result = input.accumulate(square)

        XCTAssertEqual(expected, result)
    }

    func testAccumulateUpcases() {
        let input = ["hello", "world"]
        let expected = ["HELLO", "WORLD"]
        func toUpper(_ input: String) -> String {
            return input.uppercased()
        }
        let result = input.accumulate(toUpper)

        XCTAssertEqual(expected, result)

    }

    func testAccumulateReversedStrings() {
        let input =    ["the", "quick", "brown", "fox", "etc"]
        let expected = ["eht", "kciuq", "nworb", "xof", "cte"]
        func reverse(_ input: String) -> String {
            return input.reverse()
        }
        let result = input.accumulate(reverse)

        XCTAssertEqual(expected, result)
    }

    func testAccumulateRecursively() {
        let input =   ["a", "b", "c"]
        let expected = [
            ["a1", "a2", "a3"],
            ["b1", "b2", "b3"],
            ["c1", "c2", "c3"]
        ]
        func recurse(_ input: String) -> [String] {
            func appendTo(_ innerInput: String) -> String {
                return input+innerInput
            }
            let result = ["1", "2", "3"].accumulate(appendTo)
            return result
        }
        let result = input.accumulate(recurse)

        XCTAssertEqualMultiArray(expected, result)
    }

    static var allTests: [(String, (AccumulateTests) -> () throws -> Void)] {
        return [
            ("testEmptyAccumulation", testEmptyAccumulation),
            ("testAccumulateSquares", testAccumulateSquares),
            ("testAccumulateUpcases", testAccumulateUpcases),
            ("testAccumulateReversedStrings", testAccumulateReversedStrings),
            ("testAccumulateRecursively", testAccumulateRecursively),
        ]
    }
}

LinuxMain.swift

import XCTest
@testable import AccumulateTests

XCTMain([
    testCase(AccumulateTests.allTests),
    ])
//Solution goes in Sources
import Foundation

extension Array {

  func accumulate<T>(_ closure: (Element) -> T) -> [T] {
    var array = [T]()
    for item in self {
      let result = closure(item)
      array.append(result)
    }
    return array
  }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.
Avatar of mannylopez
mannylopez
Solution Author
commented 73 days ago

Swift documentation on Generics

mannylopez's Reflection

Used Swift docs on generics: https://docs.swift.org/swift-book/LanguageGuide/Generics.html