Code and Life

Programming, electronics and other cool tech stuff

Project Euler Problem 1 with Clojure, Python, Javascript and C++

I've long thought about learning Lisp. Some time ago I ran across Clojure and the map, set and vector implementations felt like a modern addition. It's running on top of JVM which is nice in a sense, but a major pain in the ass when installing. Well, I swallowed my wow to never install JDK again and got Clojure running quite painlessly.

To learn the ropes, I thought it would be a fun idea to rewrite Project Euler problems 1-10 with Clojure to see how it would compare against my language of choice for these types of algorithmic problems, Python.

Just to make it more fun, I decided to implement them in my second favorite language, Javascript as well. Since ECMAScript 9, it's actually a pretty powerful and concise language, and coupling it with Node.js unleashes some serious usage options outside just web pages. Npm dependency hell sucks, but that's a topic for another post. For more bare metal, I'm also doing C++ (basically sticking to C functionality until maps and sets make themselves useful). Let's see how the languages stack up!

Project Euler Problem 1

The first problem in Project Euler is simple, add up numbers below 1000 that are divisible with either 3 or 5 (or both). Modulo operator % can be used to get the remainder of a number when divided by 3 and 5, and basically we add all numbers that have either modulo as zero.

Python 3

With Python, the most concise implementation is to use the sum(iterable) and a list comprehension, netting us a nice one-liner:

print(sum(i for i in range(1000) if i%3==0 or i%5==0))

C++

C++ needs a bit of boilerplate to print stuff, and does not have list comprehension that is as concise, so better just to use a for loop:

#include <iostream>

using namespace std;

int main() {
    int s = 0;
    for(int i=1; i<1000; i++)
        if(i%3==0 || i%5==0) s += i;
    cout << s << endl;
}

Javascript

Javascript is essentially the same as above, with a bit less boilerplate:

let s = 0;
for(let i=1; i<1000; i++)
    if(i%3==0 || i%5==0) s += i;
console.log(s);

If we'd like to make it more functional, Javascript filter works nicely. With ES9 we can even create an array [0, 1, 2, ..., 999] with a nice hack:

console.log([...Array(1000).keys()]
  .filter(i => i%3==0 || i%5==0)
  .reduce((a, b) => a + b, 0));

Clojure

Finally we get to the fun stuff. Or the not-so-fun: Clojure is heavily favoring REPL and the actual project with Leiningen are ten-file affairs that are just cumbersome to run. Thankfully clojure p1.clj did the trick by itself.

(println (apply + (filter #(or (= (mod % 3) 0) (= (mod % 5) 0)) (range 1000))))

With the ->> operator we can make it perhaps somewhat easier to read:

(println (->> (range 1000)
(filter #(or (= (mod % 3) 0) (= (mod % 5) 0)))
(apply + )))

My personal favorite is to define a simple ok function instead of the anonymous one and use that in the oneliner to make a nice two-liner:

(defn ok [x] (or (= (mod x 3) 0) (= (mod x 5) 0)))
(println (apply + (filter ok (range 1000))))

Conclusions from Problem 1

There is a nice Polish notation feel in the Clojure versions that make me think of some scientific calculator (like bc). It is also quite interesting to note that Javascript with its array filtering can be quite functional when you want.

Personally, the Python one-liner is the cleanest to my eye, which may be because I'm familiar with the syntax.

comments