Elegant solution for inverting zip?

G

Gregory Brown

Hi folks,

I came across something I thought should have an obvious answer and
came up blank. I'm hoping folks could give me a nice solution to this
problem.

Given the output below:
a = [1,2,3,4].zip([5,6,7,8])
=> [[1, 5], [2, 6], [3, 7], [4, 8]]


I'd like to recover the original two arrays, something like

unzip(a) #=> [[1,2,3,4],[5,6,7,8]]

The best ordinary solution I could come up with was this:

b = a.each_with_object([[],[]]) do |pair, memo|
memo[0] << pair[0]
memo[1] << pair[1]
end

Shorter, but perhaps weirder, is:

require "matrix"
b = Matrix[*a].column_vectors.map(&:to_a)

Although either of these solutions are likely good enough for my
needs, neither feel natural to me. Anyone have something better?

-greg
 
D

David A. Black

Hi --

Hi folks,

I came across something I thought should have an obvious answer and
came up blank. I'm hoping folks could give me a nice solution to this
problem.

Given the output below:
a = [1,2,3,4].zip([5,6,7,8])
=> [[1, 5], [2, 6], [3, 7], [4, 8]]


I'd like to recover the original two arrays, something like

unzip(a) #=> [[1,2,3,4],[5,6,7,8]]

a.transpose, n'est-ce pas?


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now available: The Well-Grounded Rubyist (http://manning.com/black2)
Training! Intro to Ruby, with Black & Kastner, September 14-17
(More info: http://rubyurl.com/vmzN)
 
G

Gregory Brown

require "matrix"
b = Matrix[*a].column_vectors.map(&:to_a)

*facepalm* Array#transpose is what I needed, I can't believe I forgot
that. Thanks goes to David Black via IM.

-greg
 
B

Brian Candler

Gregory said:
require "matrix"
b = Matrix[*a].column_vectors.map(&:to_a)

*facepalm* Array#transpose is what I needed, I can't believe I forgot
that. Thanks goes to David Black via IM.

That's funny - I was just trying to do more or less the same thing the
other day. Given an array of [k,v] pairs, I needed to turn it into an
array of k's and an array of v's.

I searched for a built-in method to do this, couldn't find it, so went
for the obvious solution:

ks = src.collect { |k,v| k }
vs = src.collect { |k,v| v }

But now I know a better way:

ks, vs = src.transpose

Thanks for sharing!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,734
Messages
2,569,441
Members
44,832
Latest member
GlennSmall

Latest Threads

Top