5

Given an array:

arr = [['a', '1'], ['b','2'], ['c', '3']] 

Whats the best way to split it into two arrays?

For example from the array above I want to get the following two arrays:

first = ['a','b','c']  
second = ['1', '2', '3'] 

Can i do this using collect?

1
  • 1
    Array.unzip would come handy here. unfortunately, there is no one .. Commented Jul 5, 2010 at 18:18

4 Answers 4

15

ok i just stumbled upon arr.transpose

arr = [['a', '1'], ['b','2'], ['c', '3']].transpose 

first = arr[0] 

second = arr[1] 

compared to the answers above arr.zip, arr.map, and the foreach, which is more efficient? Or which is the most elegant solution?

OR (Thanks to comment by Jörg W Mittag - see comment below) first, second = arr.transpose

Sign up to request clarification or add additional context in comments.

4 Comments

Transpose is the most elegant solution IMHO (but I'm a mathematician). I am unsure of which is the most efficient, but I'd wager that zip, transpose and foreach are pretty much the same, and map is slightly slower. Foreach will have an advantage if you don't want all of the elements in each row (e.g. two out of three or something).
This is basically the whole point of transpose, so it is almost guaranteed to be the most efficient. The others have slightly more moving parts, which usually leads to sightly less efficiency. I doubt the difference is usually that huge. The transpose method is certainly the most readable, though, so that would be its biggest plus in my book. (I'm always reluctant to say one method is the most efficient, period, because performance quirks in different versions of Ruby will usually make a liar of me someday.)
You can use destructuring bind: first, second = arr.transpose. Much more elegant. And since we are waxing on performance here: the JRuby team is working on an aggressively optimizing compiler which can eliminate the intermediate arrays when using destructuring bind, multiple assignments, multiple return values, splat arguments and the like. (In fact, the compiler is so good that its author has asked them to rewrite some of the Java portions of JRuby in Ruby because it would actually be faster.)
@You But zip is for mathematicians. en.wikipedia.org/wiki/Anamorphism :-)
4

Using the zip method is quite elegant as well:

arr[0].zip *arr[1..-1]
first = arr[0]
second = arr[1]

1 Comment

...this is pretty much the same thing as doing arr.transpose, though.
1
arr = [['a', '1'], ['b','2'], ['c', '3']]

a = []
b = []

arr.each{ |i| a << i[0]; b << i[1] }

2 Comments

hmm ok i just stumbled upon arr.traspose arr = [['a', '1'], ['b','2'], ['c', '3']].transpose first = arr[0] second = arr[1] i wonder which is more effecient
i think it won't matter for 3 items :-) try some timing tests using larger items and some data that resembles your real data
0

You can do this via collect (an alias of map), but not in a single operation, because map/collect always returns a single Array. You could do

first = arr.map { |element| element[0] }   
second = arr.map { |element| element[1] }

which has the disadvantage of iterating over arr twice. However, that shouldn't normally be a problem, unless you are dealing with a large amount of elements or this operation has to run a large number of times.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.