Аккумулятор для each_with_object продолжает повторную инициализацию
Я пытаюсь написать обобщенное декартово произведение, где входные данные [n1, n2, ...ni] производят выходные данные, которые являются массивом [m1, m2, ...mi] для всех mj, таких, что 0 <= mj Это дает следующий вывод:#!/usr/bin/ruby
def gcp(dims)
first = dims.shift
dims.each_with_object((0...first).to_a) do |dim, v|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [0, 1, 2], dim: 4
[[0, 0], [0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2], [1, 3], [2, 0], [2, 1], [2, 2], [2, 3]]
p
Метод является проходным, поэтому возвращаемое значение блока должно быть [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
на первой итерации, и это должно быть значение v
на второй итерации, если я серьезно не понял each_with_object
,
2 ответа
Каждая итерация получает один и тот же объект, поэтому вам нужно либо изменить объект внутри блока, либо использовать reduce
,
def gcp(dims)
first = dims.shift
dims.reduce((0...first).to_a) do |v, dim|
puts "\nv: #{v}, dim: #{dim}"
p v.product((0...dim).to_a)
end
end
gcp([3,2,4])
Результаты в:
v: [0, 1, 2], dim: 2
[[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]]
v: [[0, 0], [0, 1], [1, 0], [1, 1], [2, 0], [2, 1]], dim: 4
[[[0, 0], 0], [[0, 0], 1], [[0, 0], 2], [[0, 0], 3], [[0, 1], 0], [[0, 1], 1], [[0, 1], 2], [[0, 1], 3], [[1, 0], 0], [[1, 0], 1], [[1, 0], 2], [[1, 0], 3], [[1, 1], 0], [[1, 1], 1], [[1, 1], 2], [[1, 1], 3], [[2, 0], 0], [[2, 0], 1], [[2, 0], 2], [[2, 0], 3], [[2, 1], 0], [[2, 1], 1], [[2, 1], 2], [[2, 1], 3]]
Признаюсь, я не до конца понимаю вопрос, но я обратился к аналогичной проблеме, которая может объяснить, почему v
не обновляется вашим кодом.
Давайте пройдемся по вашему коду, возвращая желаемый результат, а не отображая его по пути.
dims = [3,2,4]
first = dims.shift
#=> 3
dims
#=> [2, 4] dims
Выражение
dims.each_with_object((0...first).to_a) do |dim, v|
v.product((0...dim).to_a)
end
фактически так же, как
v = []
dims.each do |dim|
v.product((0...dim).to_a)
end
v #=> []
Тот v
по-прежнему пустой массив в конце не должно быть сюрпризом, так как значение v
не изменяется внутри цикла. Возвращаемое значение v.product((0...dim).to_a)
выброшен в космос, больше никогда его не увидеть. Вам нужен оператор присваивания внутри цикла.
Теперь рассмотрим следующее.
dims = [3,2,4]
v = []
dims.each do |n|
v << (0...n).to_a
end
v #=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
(или же v.push((0..n).to_a)
). Чтобы использовать Enumerable#each_with_object, мы изменили бы приведенный выше код, удалив первый (v = []
) и последний (v
) заявления, меняющиеся each
в each_with_object([])
(аргумент, являющийся начальным значением объекта, который будет возвращать метод) и добавьте блочную переменную v
, который содержит объект:
dims.each_with_object([]) do |n,v|
v << (0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
Мы можем упростить это, используя Emumerable # map:
dims.map do |n|
(0...n).to_a
end
#=> [[0, 1, 2], [0, 1], [0, 1, 2, 3]]
В зависимости от ваших потребностей, вы можете использовать Emumerable # flat_map:
dims.flat_map do |n|
(0...n).to_a
end
#=> [0, 1, 2, 0, 1, 0, 1, 2, 3]