Что такое "Ruby way" для одновременной итерации по двум массивам
Больше синтаксического любопытства, чем проблема для решения...
Я имею два массива одинаковой длины и хочу их перебирать одновременно - например, для вывода обоих значений по определенному индексу.
@budget = [ 100, 150, 25, 105 ]
@actual = [ 120, 100, 50, 100 ]
Я знаю, что я могу использовать each_index
и индексировать в массивы так:
@budget.each_index do |i|
puts @budget[i]
puts @actual[i]
end
Есть ли способ Ruby сделать это лучше? Что-то вроде этого?
# Obviously doesn't achieve what I want it to - but is there something like this?
[@budget, @actual].each do |budget, actual|
puts budget
puts actual
end
Ответы
Ответ 1
>> @budget = [ 100, 150, 25, 105 ]
=> [100, 150, 25, 105]
>> @actual = [ 120, 100, 50, 100 ]
=> [120, 100, 50, 100]
>> @budget.zip @actual
=> [[100, 120], [150, 100], [25, 50], [105, 100]]
>> @budget.zip(@actual).each do |budget, actual|
?> puts budget
>> puts actual
>> end
100
120
150
100
25
50
105
100
=> [[100, 120], [150, 100], [25, 50], [105, 100]]
Ответ 2
Используйте метод Array.zip
и передайте ему блок для последовательного итерации соответствующих элементов.
Ответ 3
Существует еще один способ повторить итерацию по двум массивам с помощью счетчиков:
2.1.2 :003 > enum = [1,2,4].each
=> #<Enumerator: [1, 2, 4]:each>
2.1.2 :004 > enum2 = [5,6,7].each
=> #<Enumerator: [5, 6, 7]:each>
2.1.2 :005 > loop do
2.1.2 :006 > a1,a2=enum.next,enum2.next
2.1.2 :007?> puts "array 1 #{a1} array 2 #{a2}"
2.1.2 :008?> end
array 1 1 array 2 5
array 1 2 array 2 6
array 1 4 array 2 7
Перечислители являются более мощными, чем используемые выше примеры, поскольку они позволяют использовать бесконечные серии, параллельную итерацию, среди других методов.
Ответ 4
В дополнение к a.zip(b).each{|x,y| }
, как говорили другие, вы также можете сказать [a,b].transpose.each{|x,y| }
, что кажется мне чуть более симметричным. Наверное, не так быстро, потому что вы создаете дополнительный массив [a,b]
.
Ответ 5
В связи с исходным вопросом для итерации по массивам неравной длины, где вы хотите, чтобы значения циклировались вокруг, вы можете использовать
[1,2,3,4,5,6].zip([7,8,9].cycle)
и Ruby даст вам
[[1, 7], [2, 8], [3, 9], [4, 7], [5, 8], [6, 9]]
Это избавит вас от значений nil
, которые вы получите, просто используя zip
Ответ 6
Простое сжатие двух массивов вместе хорошо работает, если вы имеете дело с массивами. Но что, если вы имеете дело с бесконечными счетчиками, например, такими как:
enum1 = (1..5).cycle
enum2 = (10..12).cycle
enum1.zip(enum2)
терпит неудачу, потому что zip
пытается оценить все элементы и объединить их. Вместо этого сделайте следующее:
enum1.lazy.zip(enum2)
Этот lazy
сохраняет вас, сделав результирующий счетчик ленивым.
Ответ 7
Как насчет компрометации и использования #each_with_index?
include Enumerable
@budget = [ 100, 150, 25, 105 ]
@actual = [ 120, 100, 50, 100 ]
@budget.each_with_index { |val, i| puts val; puts @actual[i] }