Elegant solution for inverting zip?

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

Hi –

On Tue, 14 Jul 2009, Gregory B. wrote:

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

On Tue, Jul 14, 2009 at 9:27 AM, Gregory
Brown[email protected] wrote:

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

Gregory B. wrote:

On Tue, Jul 14, 2009 at 9:27 AM, Gregory
Brown[email protected] wrote:

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!