Saturday 19 October 2013

Beautiful code

Non-coders often look at me slightly suspiciously when I tell them that writing code is creative in much the same way that art, music, English, and philosophy are creative. Today I applied for an internship. One of the questions on the application form asked you to find the sum of integers, where integers which were multiples of three or five were to be summed twice. A very obvious approach to the problem would be (all examples written in Python):

s = 0
for i in range(0,1001):
if i % 3 == 0 or i % 5 == 0:
s += i
s += i
print s

Which simply loops through all the numbers and keeps track of the total. If the number divided by three or five gives a remainder of zero, then that particular number is added twice.

Another option, one line shorter but a bit less clear:

r = range(0,1001)
for i,v in enumerate(r):
if v % 3 == 0 or v % 5 == 0:
r[i] = 2 * v
print sum(r)

This loops through the list of numbers, keeping track of the index and the value. If any number is a multiple of three or five, it multiplies it by two in place. Finally, it sums the list. (No, I'm not suggesting that you code like this.)

If you want to do it in a single line of code, it's not that difficult:

print sum([2 * x if (x % 3 == 0 or x % 5 == 0) else x for x in range(1,1001)])

Using a neat Python list comprehension, we can look at each number, and add either that number or two times that number, depending on whether it is a multiple of three or five, to a new list, and then sum that. It seemed elegant and efficient enough, and it's what I handed in as my solution.

But then afterwards I realised an arguably better way to do it (though it doesn't use list comprehensions, so I'm petulantly going to argue that it's not necessarily better, solely on the basis that I like list comprehensions)

print sum(set(range(3,1001,3) + range(5,1001,5))) + sum(range(1,1001))

That uses fewer characters, is much more efficient and is more beautiful. It creates two different lists, one of all the multiples of threes, one of fives, and sums the set of the union of these two lists, and then adds the sum of all the numbers in the original range. No if statements, no loops, and no mods. 

Now at least if I don't get the internship I can convince myself that I would have got it if I'd only taken those extra couple of minutes before pressing the submit button.

No comments:

Post a Comment