In trying to learn Clojure and wrap my head around good functional programming, and hoping to learn more idiomatic Clojure, I have started working through the Project Euler problems. In doing this, I have also setup a repository on github.com to keep track of my progress, which can be found at https://github.com/stevenproctor/project-euler-clojure. My approach to Problem 3 can be found here.
Problem 4 of Project Euler is described as:
Find the largest palindrome made from the product of two 3-digit numbers.
The solution I came up with is:
(ns project-euler.core (:require [clojure.string :as string])) (defn is-palindrome? [s] (= (str s) (string/join (reverse (str s))))) (defn problem4 [] (apply max (filter is-palindrome? (for [x (range 100 1000) y (range 100 1000)] (* x y)))))
As I want to use the join function in the clojure.string namespace, I added the :require keyword and aliased clojure.string as string using the :as keyword from the namespace macro.
The function is-palindrome? converts the value into a string, reverses the stream of characters in the string and then joins them back together and then compares it with the value as a string.
As defined problem4 does the meat of the work, by using a for loop over the set of of values from 100 to 999 for the binding of x and y, and multiplies x and y for each combination. This set is then filtered against the is-palindrome function, and the filtered sequence is then passed to the max function via apply.
Again, I would love comments and suggestions on my solution to this problem, and if there are tweaks to make it more Clojure-ish.
**Update**
My solution to Problem 5 has been posted here.
–Proctor
#1 by Sonia Hamilton on May 30, 2012 - 23:36
Hi Proctor – a nice solution. I’m doing a similar thing (deliberate practice, katas), but working through the 4clojure.com exercises first.
A possible performance improvement – in the *for* you’re calculating each number twice (eg x = 100 y = 101 then x = 101 y =100). Can you think of a better way of doing this?
PS which WordPress plugin are you using to nicely format your code??
#2 by Proctor on May 31, 2012 - 16:09
Sonia,
I have done some of the exercises on 4clojure.com as well, as well as the Clojure Koans. I had also been hearing off and on about Project Euler, so I decided I might try some of these problems as well. I figured I might as well blog about my solutions so that I could get feedback, so this is where I started.
I thought about the fact that I would likely be doing extra multiplication as you pointed out, but was unsure if there was a way to do something along the lines of (for [x (range 100 1000) y [x 1000] …..). Now that you bring that up, I will have to try it out and report back on my findings.
As far as the WordPress plugin, I am simply using the put a sourcecode wordpress tag feature that one gets with a blog at wordpress.com which can be found here.
I would be curious to see your solutions 4clojure.com if you decide to post them as you progress on your journey of learning Clojure as well.
–Proctor
#3 by Sonia Hamilton on June 1, 2012 - 06:51
Hi Proctor, to reduce the number of loops you could use a :while in your list comprehension. For example:
(for [x (range 1 5) y (range 1 5)] [x y])
gives:
([1 1] [1 2] [1 3] [1 4] [2 1] [2 2] [2 3] [2 4] [3 1] [3 2] [3 3] [3 4] [4 1] [4 2] [4 3] [4 4])
whereas:
(for [x (range 1 5) y (range 1 5) :while (>= x y) ] [x y] )
gives:
([1 1] [2 1] [2 2] [3 1] [3 2] [3 3] [4 1] [4 2] [4 3] [4 4])
In your case the extra multiplications aren’t a worry, but this may come in handy for more expensive calculations.
I’ll probably start posting my 4clojure problems once I get into the more interesting ones. I’ve done the first 70 problems so far, but these early ones are more focussed on learning the mechanics of the language. I had a look at Clojure Koans and Euler too – I’ll get on to them later 🙂
Thanks for the pointer on code formatting, I’ve setup SyntaxHighlighter on my blog!
Sonia.