Какой самый лучший и быстрый способ объединить 3 параллельных массива в Ruby - PullRequest
1 голос
/ 12 февраля 2012

Я хотел бы объединить массивы @a, @b и @c в один массив с несколькими элементами данных, например OpenStruct:

@a = ["my", "foo", "bar"]
@b = ["yan", "can", "cook"]
@c = ["in", "your", "dreams"]

, результат будет выглядеть как:

[
  { :a => "my",  :b => "yan",  :c => "in" },
  { :a => "foo", :b => "can",  :c => "your" },
  { :a => bar,   :b => "cook", :c => "dreams" }
]

Какой самый быстрый способ сделать это?Должен ли я рассмотреть другой класс?

Ответы [ 5 ]

4 голосов
/ 12 февраля 2012

Вот одно из решений, я не совсем уверен, что оно самое подходящее:

@a.zip(@b, @c).map {|t| {:a => t[0], :b => t[1], :c => t[2]}}
3 голосов
/ 12 февраля 2012

Функциональный подход:

[@a, @b, @c].transpose.map { |xs| Hash[[:a, :b, :c].zip(xs)] }
#=> [{:a=>"my", :b=>"yan", :c=>"in"}, {:a=>"foo", :b=>"can", :c=>"your"}, {:a=>"bar", :b=>"cook", :c=>"dreams"}] 
2 голосов
/ 12 февраля 2012

Лучший способ узнать самый быстрый способ - это сделать тест.На основании предыдущих ответов:

require 'benchmark'

@a = ["my", "foo", "bar"]
@b = ["yan", "can", "cook"]
@c = ["in", "your", "dreams"]
$n = 500_000

Benchmark.bmbm do |x|
  x.report("Boris Strandjev") do $n.times do
    @a.zip(@b, @c).map {|t| {:a => t[0], :b => t[1], :c => t[2]}}
  end end
  x.report("tokland") do $n.times do
    [@a, @b, @c].transpose.map { |xs| Hash[[:a, :b, :c].zip(xs)] }
  end end
  x.report("mu is too short") do $n.times do
    (0 ... [@a, @b, @c].max_by(&:length).length).map { |i| { :a => @a[i], :b => @b[i], :c => @c[i] } }
  end end
  x.report("KL-7") do $n.times do
    @a.each_with_index.map { |a, i| { :a => a, :b => @b[i], :c => @c[i] } }
  end end
end

Вывод:

Rehearsal ---------------------------------------------------
Boris Strandjev   4.540000   0.015000   4.555000 (  4.571261)
tokland           7.145000   0.000000   7.145000 (  7.268415)
mu is too short   5.304000   0.047000   5.351000 (  5.560318)
KL-7              4.914000   0.000000   4.914000 (  5.030287)
----------------------------------------- total: 21.965000sec

                      user     system      total        real
Boris Strandjev   4.462000   0.016000   4.478000 (  4.553260)
tokland           7.129000   0.031000   7.160000 (  7.309418)
mu is too short   5.366000   0.031000   5.397000 (  5.447312)
KL-7              4.898000   0.016000   4.914000 (  4.997286)
1 голос
/ 12 февраля 2012

Если нет необходимости беспокоиться о массивах разной длины, я думаю, что это самый быстрый способ (поскольку он выполняет итерации по массиву только один раз):

@a.each_with_index.map { |a, i| { :a => a, :b => @b[i], :c => @c[i] } }
0 голосов
/ 12 февраля 2012

Примерно так должно работать:

(0 ... [@a, @b, @c].max_by(&:length).length).map { |i| { :a => @a[i], :b => @b[i], :c => @c[i] } }

Это не предполагает, что они все одинаковой длины, но вы получите nil значения, если они не будут.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...