Array decomposition in Ruby
One of the things that impress me the most about Haskell is the combination of
expressive power and readability afforded by its’ pattern matching. As a simple
example, here is a clever way of reversing a Data.List
(roughly equivalent to
Ruby’s Array
):
1 reverse' :: [a] -> [a]
2 reverse' [] = []
3 reverse' (x:xs) = reverse'(xs) ++ [x]
4 -- reverse' [1, 2, 3, 4]
5 -- [4,3,2,1]
For Haskell infidels let me explain that with the (x:xs)
syntax the x
variable represents the first element of the list while xs
represents the
rest.
What I really like about this way of writing algorithms is that they read like human-friendly description of a problem (definition of what it means for an list to be reversed) rather than a machine-friendly list of steps how solve it.
Thankfully as of Ruby 1.9 I can use at least some of that goodness with the
splat operator and array decomposition. In the example below head, *tail = arr
is a rough equivalent of Haskell’s (x:xs)
.
1 def reverse(arr)
2 return arr unless arr.length > 1
3 head, *tail = arr
4 reverse(tail) + [head]
5 end
6 reverse([1, 2, 3, 4])
7 #=> [4, 3, 2, 1]
That alone is pretty cool even tough there is no pattern matching possible here so we’re using an early return to get a similar boost in readability. And yet it gets even better since array decomposition with the splat operator can get fancier than that. Let’s take your simple coding interview warm-up question - checking for palindromes:
1 def palindrome?(word)
2 return true if word.length < 2
3 first, *middle, last = word.chars
4 first == last && palindrome?(middle.join)
5 end
What’s going on in line #3 above is that first
is assigned to the first value
of the array, last
to the last one and middle
captures the entire space
inbetween, as an Array
. In case there is nothing between the two extremes
middle
becomes an empty container and evaluates to ''
after joining.
Once you get a handle on the splay operator and array decomposition you can start using it to greatly improve the readability of your code, especially that operating on arrays.