November 24, 2014

Project Euler p. 1

The first problem is fairly straight-forward:

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

Ok, so we need something that looks a little something like this:

(defn solve
  "Solve for x < 1000"
  []
  (solve-for-x-lower-than 1000))

First thing to do, what qualifies a number x as a multiple of 3 or 5?

(defn multiple-of-3-or-5?
  "Returns true if the argument is a multiple of 3 or 5"
  [x]
  (or (zero? (mod x 3)) (zero? (mod x 5))))

Nothing really groundbreaking going on here. But now we know how to decide whether a number is to be included or not.

Next we need to find these numbers in a collection of numbers:

(defn find-multiples-of-3-or-5
  "Given a collection, returns those that are multiples of 3 or 5"
  [coll]
  (filter multiple-of-3-or-5? coll))

Same here, the clojure function filter and our predicate function saves the day. But where should the collection come from? A brief look in the Clojure docs gives (range n m) which will construct a sequence of numbers ranging from n up to m non-inclusive. Great! this means that we can use (range 1 1000) to get the sequence of numbers we need. We can them hand that sequence off to find-multiples-of-3-or-5 and sum the result:

(defn solve-for-x-lower-than
  "Solve for all values x where: 1 < x < n."
  [n]
  (reduce + (find-multiples-of-3-or-5 (range 1 n))))

My complete solution is thus:

(ns euler.p01)

(defn multiple-of-3-or-5?
  "Returns true if the argument is a multiple of 3 or 5"
  [x]
  (or (zero? (mod x 3)) (zero? (mod x 5))))

(defn find-multiples-of-3-or-5
  "Given a collection, returns those that are multiples of 3 or 5"
  [coll]
  (filter multiple-of-3-or-5? coll))

(defn solve-for-x-lower-than
  "Solve for all values x where: 1 < x < n."
  [n]
  (reduce + (find-multiples-of-3-or-5 (range 1 n))))

(defn solve
  "Solve for x < 1000"
  []
  (solve-for-x-lower-than 1000))

(solve)

After being invoked, the return value was tested on Project Euler, and it turns out it was correct. Nice!

Now this code might be naive, inefficient, verbose or just plain bad. But I had to work with what I already knew about Clojure, which was just a couple of short tutorials to get familiar with the REPL and the syntax. Hopefully the code will get better and better.

© Sebastian Hörberg 2018

Powered by Hugo & Kiss.