patternswiftMinor
Project Euler #4 (largest palindrome product) in Swift
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
The
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
The problem constant
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:
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:
In the above code, there is no point in testing smaller right values if they will never beat the current largest palindrome.
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.