HiveBrain v1.2.0
Get Started
← Back to all entries
patternswiftMinor

Project Euler #4 (largest palindrome product) in Swift

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
swiftproductlargestpalindromeprojecteuler

Problem

A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.


Find the largest palindrome made from the product of two 3-digit numbers.

What I've so far learned about Swift is that while the Playground is very cool for tinkering around, it definitely does not like big loops. So this time, I coded parts in the playground, but moved it over to an actual executable project to run the final code.

I'm interested in knowing any Swift tricks I missed. I did implement a new trick I learned in this solution, the stride feature.

import Foundation

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

extension Int {
    func isPalindrome() -> Bool {
        return self == self.reversed()
    }

    func reversed() -> Int {
        var original: Int = self
        var reversed: Int = 0

        while original > 0 {
            reversed *= 10
            reversed += original % 10
            original /= 10
        }

        return reversed
    }
}

func largestPalindrome() {
    var left: Int = 999
    var right: Int = 999

    var largestPalindrome: Int = 0

    for left in stride(from: 999, through: 100, by: -1) {
        for right in stride(from: left, through: 100, by: -1) {
            let product: Int = left * right
            if product > largestPalindrome && product.isPalindrome() {
                largestPalindrome = product
            }
        }
    }

    println(String(largestPalindrome))
}

printTimeElapsedWhenRunningCode("Largest Palindrome", largestPalindrome)


The printTimeElapsedWhenRunningCode function is borrowed from Brad Larson's answer here, and on my computer, it says the code is running in about 0.27 to 0.28 seconds.

Solution

Style

The reversed() function is only called from the isPalindrome function. Since the isPalindrome function is a 1-liner, it strikes me that there is no value added by exposing the reversed functionality at all, and that it can all be emedded in to the isPalindrome() call. There is no need for the method extraction in this case, it is overkill, and adds no significant value, while adding bulk to an extension on Int.

The problem constant 999 strikes me as being a good candidate for an input parameter. Instead you have encoded it as a magic number (three times) in the largestPalindrome() method. I feel it is more natural to have the input defined in the same way as the problem, use 3-digit numbers:

func largestPalindrome(limit: Int) -> Int {


note, the function receives the input limit, and it also returns the largestPalindrome from that limit. Note that the single-responsibility principle suggests that a function should return the value, and that you should print the result outside the function. The print in the function is.... ugly.

The code to turn the value 3 (for 3 digit numbers), would be:

  • limit max (exclusive) \$10^3\$



  • limit min (inclusive) \$10^{(3 - 1)}\$



Performance

There is a trivial, but effective optimization available for you, by breaking the inner loop when the product will always be less than the previously found largest.

Consider the code:

for left in stride(from: 999, through: 100, by: -1) {
    for right in stride(from: left, through: 100, by: -1) {
        let product: Int = left * right
        if product > largestPalindrome {
            if product.isPalindrome() {
                largestPalindrome = product
            }
        } else {
            break
        }
    }
}


In the above code, there is no point in testing smaller right values if they will never beat the current largest palindrome.

Code Snippets

func largestPalindrome(limit: Int) -> Int {
for left in stride(from: 999, through: 100, by: -1) {
    for right in stride(from: left, through: 100, by: -1) {
        let product: Int = left * right
        if product > largestPalindrome {
            if product.isPalindrome() {
                largestPalindrome = product
            }
        } else {
            break
        }
    }
}

Context

StackExchange Code Review Q#60963, answer score: 8

Revisions (0)

No revisions yet.