Reputation: 899
Is there a general way of doing this ?
Each sub array will be of the same length.
c = [[1,1,1,1], [2,2,2,2], [3,3,3,3]]
c[0].zip(c[1], c[2])
=> [[1,2,3][1,2,3],[1,2,3],[1,2,3]]
Thank you.
Upvotes: 1
Views: 691
Reputation: 110725
Edit: I discovered why my method is so fast, which may have implications that are both good and bad, depending on how the results are to be used. Suppose
c = [[1,1,1],[2,2,2]]
Then
d = [c.map(&:first)]*c.first.size #=> [a, b, c]
where:
a = b = c = [1,2]
but that's because:
a.object_id = b.object_id = c.object.id
So the "bad" is that if an element of d
is changed, all the elements in that row are changed to the same value. The "good" is that if the array d
will not be changed, not only is this method fast, but it requires very little storage to save the (representation) of the resulting array d
.
The truth, however, is that if d
is not to be changed, it is pointless to create it. Instead, the code should be refactored so that only the first element of d
is used in subsequent operations. (This remark applies to all the methods, of course.)
end of edit
If you intend each element (row) of c
to contain elements that are all equal to one another, and they are all the same size, as in your example, you could do this:
[c.map(&:first)]*c.first.size
Out of curiosity I decided to benchmark this method and the two @sawa offered.
Benchmarking code
require 'benchmark'
def sawa_zip(c) c.first.zip(*c.drop(1)) end
def sawa_transpose(c) c.transpose end
def cary(c) [c.map(&:first)]*c.first.size end
def bench_em(n, m, iterations)
puts "n = #{n}, m = #{m}, interations = #{iterations}\n"
c = n.times.map { Array.new }.map.with_index { |_,i| Array.new(m,i) }
Benchmark.bm(%w[sawa_zip, sawa_transpose, cary].map(&:size).max) do |bm|
bm.report('sawa_zip') do
iterations.times do
sawa_zip(c)
end
end
bm.report('sawa_transpose') do
iterations.times do
sawa_transpose(c)
end
end
bm.report('cary') do
iterations.times do
cary(c)
end
end
end
end
bench_em(200, 300,5)
bench_em(2000, 3000,5)
bench_em(10000, 15000,1)
Benchmark results
It should be kept in mind that this comparison is only valid when all elements in each row of the matrix are equal. I had expected the method I suggested to be relatively fast, but not as fast as indicated by the results.
n = 200, m = 300, interations = 5
user system total real
sawa_zip 0.010000 0.000000 0.010000 ( 0.007858)
sawa_transpose 0.000000 0.000000 0.000000 ( 0.006568)
cary 0.000000 0.000000 0.000000 ( 0.000113)
n = 2000, m = 3000, interations = 5
user system total real
sawa_zip 1.010000 0.070000 1.080000 ( 1.080286)
sawa_transpose 0.800000 0.060000 0.860000 ( 0.860823)
cary 0.000000 0.000000 0.000000 ( 0.001669)
n = 10000, m = 15000, interations = 1
user system total real
sawa_zip 25.760000 0.740000 26.500000 ( 26.668127)
sawa_transpose 18.200000 0.630000 18.830000 ( 18.870150)
cary 0.000000 0.000000 0.000000 ( 0.002412)
Upvotes: 3
Reputation: 168199
To do it with zip
:
c.first.zip(*c.drop(1))
Otherwise,
c.transpose
will be a symmetric way.
Upvotes: 7