12

I have an array:

arr=[[1,2,3],[4,5],[6]],

I have the following code:

arr.transpose 

but it doesn't work,how to solve it?

I am getting

 [[1,2,3],[4,5],[6]].transpose
IndexError: element size differs (2 should be 3)
    from (irb):13:in `transpose'
    from (irb):13
    from /home/durrant

my solution:

arr.reduce(&:zip).map(&:flatten)

output:

[[1, 4, 6], [2, 5, nil], [3, nil, nil]]
4
  • 5
    What is the expected result for the given array? Commented Sep 24, 2014 at 12:15
  • Look this stackoverflow.com/questions/21455310/… to understand why #transpose didn't work. Commented Sep 24, 2014 at 12:17
  • The answer, though I can't post as such is that the number of elements have to be the same for this operation. Commented Sep 24, 2014 at 12:25
  • So, if you have [[1,2,3],[4,5,0],[6,0,0]].transpose => [[1, 4, 6], [2, 5, 0], [3, 0, 0]] that works because the number of elements in each array is the same. Commented Sep 24, 2014 at 12:26

3 Answers 3

13

Using zip as in Stefan's answer is the most straightforward, but if you insist on using transpose, then:

l = arr.map(&:length).max
arr.map{|e| e.values_at(0...l)}.transpose
# => [[1, 4, 6], [2, 5, nil], [3, nil, nil]]

Or without using either:

Array.new(arr.map(&:length).max){|i| arr.map{|e| e[i]}}
# => [[1, 4, 6], [2, 5, nil], [3, nil, nil]]
Sign up to request clarification or add additional context in comments.

2 Comments

This is the best solution for a safe-transpose. Using zip only works when the first array is bigger than the others.
Very nice. I suggest you limit your answer to #2 and merely state that it does not depend on the first subarray being the largest.
12

A similar answer was posted (but deleted) an hour earlier:

arr = [[1, 2, 3], [4, 5], [6]]

arr[0].zip(*arr[1..-1])
#=> [[1, 4, 6], [2, 5, nil], [3, nil, nil]]

The above is equivalent to:

[1, 2, 3].zip([4, 5], [6])

This approach assumes that your first sub-array is always the longest. Otherwise the result will be truncated:

arr = [[1, 2], [3, 4, 5], [6]]

arr[0].zip(*arr[1..-1])
#=> [[1, 3, 6], [2, 4, nil]]  missing: [nil, 5, nil]

2 Comments

I was looking for a safe transpose method, and used your solution. It only seems to work when the first array is bigger than all the other ones. Using it with arr.reverse returns [[6, 4, 1]] instead of [[6, 4, 1], [nil, 5, 2], [nil, nil, 3]].
@EricDuminil that's correct, I've update the answer accordingly.
1

If the length of the subarrays don’t match, an IndexError is raised.

irb(main):002:0> arr=[[1,2,3],[4,5],[6]]
=> [[1, 2, 3], [4, 5], [6]]
irb(main):003:0> arr.transpose
IndexError: element size differs (2 should be 3)
    from (irb):3:in `transpose'
    from (irb):3
    from /Users/liuxingqi/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'

should be:

irb(main):004:0> arr=[[1,2,3],[4,5,6]]
=> [[1, 2, 3], [4, 5, 6]]
irb(main):005:0> arr.transpose
=> [[1, 4], [2, 5], [3, 6]]

or

irb(main):006:0> arr=[[1,2],[3,4],[5,6]]
=> [[1, 2], [3, 4], [5, 6]]
irb(main):007:0> arr.transpose
=> [[1, 3, 5], [2, 4, 6]]

2 Comments

How did you able to answer while question is closed... Strange!!
Yeah funny, I'm curious too.

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.