有没有一般的方法呢?
每个子数组的长度都相同。
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]]
谢谢。
答案 0 :(得分:7)
使用zip
执行此操作:
c.first.zip(*c.drop(1))
否则,
c.transpose
将是一种对称的方式。
答案 1 :(得分:3)
编辑:我发现为什么我的方法如此之快,这可能会带来好的和坏的含义,具体取决于结果的使用方式。假设
c = [[1,1,1],[2,2,2]]
然后
d = [c.map(&:first)]*c.first.size #=> [a, b, c]
其中:
a = b = c = [1,2]
但那是因为:
a.object_id = b.object_id = c.object.id
所以“坏”是如果d
的元素被更改,则该行中的所有元素都将更改为相同的值。 “好”是如果数组d
不会被更改,不仅这个方法很快,而且需要很少的存储来保存结果数组d
的(表示)。
然而,事实是,如果不改变d
,那么创建它是没有意义的。相反,应该重构代码,以便在后续操作中仅使用d
的第一个元素。 (当然,这句话适用于所有方法。)
编辑结束
如果您希望c
的每个元素(行)包含彼此相等的元素,并且它们的大小都相同(如您的示例中所示),则可以执行此操作:
[c.map(&:first)]*c.first.size
出于好奇,我决定对这种方法和@sawa提供的两种方法进行基准测试。
基准代码
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)
基准测试结果
应该记住,这种比较仅在矩阵每行中的所有元素相等时才有效。我曾预料到我建议的方法相对较快,但速度不如结果所示。
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)