Ruby and elegance: Transpose
March 10, 2007I recently found that the Array class of Ruby has a zip method, which works much like Haskell’s zip function, except that it allows multiple arguments.
For example:
$ irb --simple-prompt
>> [1,2,3].zip [4,5,6], [7,8,9]
=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
The night after I did this little experiment I suddenly realized: this is a transpose function! I quickly got out of bed to document my little discovery:
def transpose(matrix)
matrix[0].zip *matrix[1..-1]
end
It’s the little things that make me like this language so much.
Update: I forgot the asterisk before matrix[1..-1]
in the above method.
Very creative! When I first read about zip in Ruby, I thought “cool, but can’t think of a way to use it.” Then I read a book on Haskell, and the zip examples were an eye opener. The functions are not quite the same, but it still gave me ideas about using it.
by Keith Lancaster March 10, 2007 at 6:38 pmDid you know Python also has zip() and map()? I’m liking Python more and more, though I’m only now actually programming a little something in it myself.
by breun March 10, 2007 at 7:53 pmThat’s http://docs.python.org/lib/built-in-funcs.html 🙂
by breun March 10, 2007 at 7:54 pm% ri Array.transpose
Array#transpose
array.transpose -> an_array
————————————————————————
Assumes that _self_ is an array of arrays and transposes the rows and columns.
a = [[1,2], [3,4], [5,6]]
by A.nony.mouse March 10, 2007 at 9:35 pma.transpose #=> [[1, 3, 5], [2, 4, 6]]
Sweet 🙂
It’s definitely shorter than GHC’s version in Haskell:
transpose :: [[a]] -> [[a]]
transpose [] = []
transpose ([] : xss) = transpose xss
transpose ((x:xs) : xss) = (x : [h | (h:t)
See also: List.hs
by chriseidhof March 11, 2007 at 9:22 amImpressive! Thank you.
by Cathy Nitchey March 15, 2007 at 3:06 amHere is another Haskell version of transpose:
foldr (zipWith (:)) (repeat [])
by petekaz May 6, 2007 at 2:28 pmI tried this but didn’t end up with the same result as the first example. If I pass in an array of arrays as it expects, I get a different result:
transpose([[1,2,3],[4,5,6],[7,8,9],[10,11,12],[13,14,15]])
=> [[1, [4, 5, 6]], [2, [7, 8, 9]], [3, [10, 11, 12]]]
This is not the same as:
[1,2,3].zip [4,5,6],[7,8,9],[10,11,12],[13,14,15]
=> [[1, 4, 7, 10, 13], [2, 5, 8, 11, 14], [3, 6, 9, 12, 15]]
Am I going something wrong, am I passing in the matrix argument incorrectly?
by Dom July 9, 2007 at 11:37 pmI want to be able to pass an array of arrays in and get the same result as calling the zip method directly on the first element of the matrix argument.
In order to get the correct you need to add an asterisk:
def transpose(matrix)
matrix[0].zip matrix[*1..-1]
end
which will unpack the array of arrays before processing.
Also, A.nony.mouse is correct – Array has a transpose method that will render the same result:
[[1,2,3][4,5,6],[7,8,9],[10,11,12],[13,14,15]].transpose
by Dom July 10, 2007 at 6:35 am=> [[1, 4, 7, 10, 13], [2, 5, 8, 11, 14], [3, 6, 9, 12, 15]]
@Dom: Whoops, you’re right. I’ve updated the post. But I’d place that asterisk before
matrix
, otherwise it has a whole different meaning.Btw, the Array.transpose method is great! [[1,2,3],%w(a b c)].transpose is a beautiful syntax for zipping arrays.
by benlenarts July 10, 2007 at 2:34 pmHey Chris, deze Ruby-implementatie is dan wel korter maar doet niet hetzelfde als de Haskellimplementatie. Vergelijk:
>> [1,2,3].zip [4,5,6], [7,8,9,10]
=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
Prelude Data.List> transpose [[1,2,3], [4,5,6], [7,8,9,10]]
[[1,4,7],[2,5,8],[3,6,9],[10]]
Het feit dat Haskell goed omgaat met lijsten van verschillende lengte is extreem handig in de situaties waar ik transpose tot nu toe in gebruikt heb.
by Martijn June 28, 2008 at 2:44 pmOne-line solution in Python:
transpose = lambda matrix: zip(*matrix)
by kj March 31, 2010 at 11:02 pmhashflare cloud mining – hashflare cloud mining, android
by NorrisJat February 26, 2020 at 12:34 am