4
\$\begingroup\$
import Foundation

func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
    let startTime = CFAbsoluteTimeGetCurrent()
    operation()
    let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
    println("Time elapsed for \(title): \(timeElapsed) s")
}    

func squaresSummed(first: Int, second: Int) -> Int {
    return (first + (second * second))
}

func solution6() {
    let firstHundredInts = [Int](1 ... 100)
    let summed = firstHundredInts.reduce(0) { $0 + $1 }
    let summedSquared = summed * summed

    let squaredSummed = firstHundredInts.reduce(0, combine: squaresSummed)

    let answer = summedSquared - squaredSummed

    println(String(answer))
}

printTimeElapsedWhenRunningCode("Sum square difference", solution6)

Some of the built in Swift stuff made this quite nice. The syntax for declaring an array which is a simple list of integers is very convenient. It runs faster than iterating through a loop to set all the values, types faster and reads better than typing all the values out by hand.

I quite like the reduce function on Swift arrays.

What could make this more Swift...-onic? What needs improvement?

\$\endgroup\$
  • \$\begingroup\$ Normally in my PE solutions I don't include printlns etc. in the methods that solve the problem. I don't want to include them in my time measurements. \$\endgroup\$ – async Sep 6 '14 at 23:11
  • 1
    \$\begingroup\$ Stick with "Swifty". It's more, Swifty. =) \$\endgroup\$ – RubberDuck Sep 6 '14 at 23:54
  • 1
    \$\begingroup\$ But I like putting the wift in Sonic. \$\endgroup\$ – nhgrif Sep 7 '14 at 0:02
6
\$\begingroup\$

First, I would suggest that the solution6() function takes a parameter for the upper bound, and returns the result instead of printing it (as also suggested by @user16547 while I was writing this answer):

func solution6(upper : Int) -> Int {
    let firstInts = [Int](1 ... upper)
    let summed = firstInts.reduce(0) { $0 + $1 }
    let summedSquared = summed * summed
    let squaredSummed = firstInts.reduce(0, combine: squaresSummed)
    return summedSquared - squaredSummed
}

printTimeElapsedWhenRunningCode("Sum square difference") {
    let answer = solution6(10_000)
    println(answer)
}

Then you use an auxiliary function squaresSummed for computing the second sum, but not for the first (and the name of that function is not very descriptive). In my opinion it is easier to understand if the shorthand notation is used for both summations:

func solution6(upper : Int) -> Int {
    let firstInts = [Int](1 ... upper)
    let summed = firstInts.reduce(0) { $0 + $1 }
    let squaredSummed = firstInts.reduce(0) { $0 + $1 * $1 }
    return summed * summed - squaredSummed
}

For an upper bound of 10,000, this took about 0.001 seconds on my MacBook Pro in Release mode.

But [Int](1 ... upper) creates an array of all that numbers, which costs time and memory. If you use a range instead

func solution6(upper : Int) -> Int {
    let firstInts = 1 ... upper
    let summed = reduce(firstInts, 0) { $0 + $1 }
    let squaredSummed = reduce(firstInts, 0) { $0 + $1 * $1 }
    return summed * summed - squaredSummed
}

the time is reduced to about 0.0002 seconds. This is about the same time needed for a simple loop

func solution6(upper : Int) -> Int {
    var summed = 0
    var squaredSummed = 0
    for i in 1 ... upper {
        summed += i
        squaredSummed += i * i
    }
    return summed * summed - squaredSummed
}

which would be the most straightforward implementation of the algorithm.

Of course the fastest and shortest solution to the PE problem would be to

Find the closed formula for 1 + 2 + ... + n and 1^2 + 2^2 + ... + n^2 and use that instead of a loop.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.