Collections, method chains and train wrecks (and SQL)

Last Friday, I got to teach about collections and closures in Ruby for ECC. That gave me an idea to write a post about one of the mistakes people coming from other languages tend to make when going into Ruby.

Let’s take the first problem from Project Euler:

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.

Looks simple enough. In pseudocode, your typical fresh grad programmer might do this:

sum <- 0
for i <- 1 to 999
  if i % 3 == 0 or i % 5 == 0
    sum += i
  end if
end for

A rubyist, however, will compress that 6 line program into a single line. Here is one possible solution:

(1..999).select { |x| x % 3 == 0 or x % 5 == 0 }.reduce(:+)

This line of code chains the 3 main components of the algorithm above:

  1. (1..999) - find a way to process numbers from 1 to 999. Here we created a Range that we can process as a whole.
  2. .select { |x| x % 3 == 0 or x % 5 == 0 } - process only the multiples of 3 and 5. Here, the method called selects only the elements that return true inside the passed block.
  3. .reduce(:+) - find the sum of the elements. Here we used the shorthand form of Ruby's reduce operation that sums the elements.

Let's try a harder example, problem 6:

(1..100).reduce(:+) ** 2 - (1..100).map { |x| x * x }.reduce(:+)

Here we see Ruby's map, which simply creates a copy of the source collection and applying the mapping function to each element. The map above is pretty trivial; we could even replace it with the long form of the reduce method.

(1..100).reduce(:+) ** 2 - (1..100).reduce(0) { |sum, x| sum + x * x }

While method chaining wouldn't be new to the novice developer, the concept of passing functions to methods, allowing greater flexibility, will be. Functional programming has been long forgotten even at the top universities in this country.

Another problem is that method chains can be too long. Some people call these chains "train wrecks". Obviously, this is a subjective matter, but one cannot deny that very long method chains are hard to debug. For example, here's one possible solution to problem 20:

(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }.reduce(:+)

This line simply:

  1. creates a range from 2 to 100 (1 is ignored in the factorial)
  2. calculate the factorial by multiplying them together
  3. convert it to a string
  4. create an array whose elements consist of single characters from the string (split("") also works)
  5. convert each element to integer
  6. calculates the sum of the elements

One way of debugging this long method chain would be to insert a tap method call to inspect the intermediate value of the chain. For example, if you do this:

(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }
.tap { |x| puts x.inspect }.reduce(:+)

you'll get the array of numbers before the reduce.

irb(main):001:0>(2..100).reduce(:*).to_s.scan(/./).map { |x| x.to_i }
.tap { |x| puts x.inspect }.reduce(:+)
[9, 3, 3, 2, 6, 2, 1, 5, 4, 4, 3, 9, 4, 4, 1, 5, 2, 6, 8, 1, 6, 9, 9, 2, 3, 8, 8 
, 5, 6, 2, 6, 6, 7, 0, 0, 4, 9, 0, 7, 1, 5, 9, 6, 8, 2, 6, 4, 3, 8, 1, 6, 2, 1,
4, 6, 8, 5, 9, 2, 9, 6, 3, 8, 9, 5, 2, 1, 7, 5, 9, 9, 9, 9, 3, 2, 2, 9, 9, 1, 5,
 6, 0, 8, 9, 4, 1, 4, 6, 3, 9, 7, 6, 1, 5, 6, 5, 1, 8, 2, 8, 6, 2, 5, 3, 6, 9, 7
, 9, 2, 0, 8, 2, 7, 2, 2, 3, 7, 5, 8, 2, 5, 1, 1, 8, 5, 2, 1, 0, 9, 1, 6, 8, 6,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
=> 648

Not exactly pretty, nor is it the most interesting use of tap, but it still gets the work done.

As a bonus, I'd just like to share a realization I had a while back.

Web developers shouldn't have to have problems with list processing because they deal with lists all the time: in SQL!

Think about it, you can define filter options in WHERE clauses, while map and reduce can be done in the SELECT clause. Assuming you have a table numbers with a column number with 100 records, each corresponding to numbers from 1 to 100, problem 6 can be solved by the following SQL statement:

SELECT SUM(number) * SUM(number) - SUM(number * number) FROM numbers

April 2011 PhRUG Meetup

Last night was supposed to be just an informal meeting; last month’s low attendance made us move from the “1-3 speakers” scheme to a “10 minute show and tell” programme. But people just kept arriving and everything went better than expected.

PhRUG meetup April 2011

And yeah, some guys from Pivotal Labs also showed up and participated in the talks.

Pivotal Labs and Friendster guys

The Pivotal guys went with some people from MOL/Friendster. The former were contracted to do some stuff for the latter, but I didn’t ask if they’re rewriting the social networking site in Ruby. (I was too busy eating pizza to eavesdrop) That’s them in the pic above, with Winston presenting in the front.

Anyway, here’s a list of the talks last night:

Thanks to Exist for sponsoring the venue, Topher for taking pictures, and Topher again (and Rad?) for the food.

For updates on future Ruby meetups, join our Google group.

Free Windows Ruby/Rails Editors: Redcar and Sublime Text 2

Last Saturday was the third time this year I’ve gone to a college to talk about Ruby and Rails. And, as expected, the general lack of experience in developing in Windows was the main cause of problems in that whole day event.

The experience wasn’t as bad as what we would have gotten had we conducted it last year, though. Installation used to be the hardest part about Rails on Windows, but thanks to RailsInstaller and RailsFTW, installing Rails on Windows nowadays is practically easier than installing it on Linux or OSX.

However, another problem still remains: the lack of good text editors for Rails on Windows. The vast majority of Ruby developers don’t use IDEs, while their choice of text editors are either OS X exclusive (TextMate) or has a steep learning curve (vim, emacs). On the Windows side, Notepad++ and Crimson Editor both have dismal Rails support.

Fortunately, there are a couple of good upcoming text editing options for Rails developers on Windows.

Redcar is a text editor written in Ruby running on top of JRuby. It’s cross-platform and free but still in alpha. It’s heavily inspired by TextMate, and it even supports some TextMate bundles.

Redcar only requires Ruby and Java. You don’t need to have JRuby; any combination of JRE and Ruby interpreters should work. Running the installation commands

$ gem install redcar
$ redcar install

will download Redcar and JRuby JAR files and install them in your local user directory. After installation, you could run Redcar just as you would run TextMate

$ redcar PATH/TO/APP

Here’s a screenshot of Redcar viewing my depressing lotto app (click to enlarge):

redcar

Sublime Text 2 is another cross-platform text editor. The original Sublime Text isn’t free, but the upcoming release is still free because it’s still in alpha.

Here’s a screenshot (click to enlarge):

sublime text 2 alpha

Sublime Text 2 doesn’t require Ruby or Java, making it more feasible to be shared around in a coding workshop with spotty internet connections (e.g. last Saturday’s event), but its eventual proprietary nature may prevent long-term development use.

EDIT: Quick write-up on Notepad++ v6.0 here.