While idly surfing around earlier, I caught this post on coderbits, announcing that some of the Practicing Ruby archives are available under a free documentation license. When I saw that one of the released articles was written by James Edward Gray II, I just had to take a look.
In case you don’t know, JEGII is a “name” in the Ruby world, and for several years he ran the weekly ruby quiz on ruby-talk. At the time I was quite active on the list, and used to really look forward to the quiz as it always provided an interesting diversion from whatever I was working on that week. I even helped out by setting the occasional quiz myself (and that one won me a signed copy of James’ book).
Anyway, his article for Practicing Ruby was a great read, and proposed a problem that I’ve not specifically come across before. Just reading the intro re-awakened the old ruby-quizzer in me, so I had to have a go. Before I read any further than the problem definition, I wrote up some code. Here’s my first version:
def score(guesses, winners, scores = [15, 10, 5, 3, 1]) guesses.zip(winners).inject([0, scores]) do |cscores, pair| guess, winner, cur_score, scores_ary = *pair, *cscores cur_score += if guess.eql? winner scores_ary.first elsif winners.include? guess 1 end || 0 [cur_score, scores_ary[1..-1]] end.first end
This works, but it feels funky in places. Using an array to pass multiple variables through the inject loop, for example, isn’t good coding. I don’t write anywhere near as much Ruby as I once did so I tend to forget things. Sure enough, reading the rest of the article reminded me that zip can take more than one argument!
This allowed me to refine my code a bit:
def score(guesses, winners, scores = [15, 10, 5, 3, 1]) guesses.zip(winners, scores).inject(0) do |cur_score, (guess, winner, score)| cur_score + if guess.eql? winner score elsif winners.include? guess 1 end || 0 end end
This is also using another little trick I’d forgotten about (Mathias Meyer had a reminder for me in this post) – tuple arguments. Inject passes in the current score, plus the current three-element array from the zipped array. By surrounding the three argument names with parenthesis, Ruby splats the array out into three variables automatically for me. Sweet!
This fun little exercise reminded why I love Ruby so much. It’s the little things: zip and inject, ‘if’ as an expression (notice the ‘end || 0’ line at the end of the if block), tuple arguments and so much more.
Right now my day job project is a rails-based proprietary webapp, where I’m obviously writing Ruby, but somehow it’s a lot less fun than little snippets like this. My new resolution is to spend a little time every week seeking out these little problems – if Ruby Quiz no longer comes to me, then I must go to it!