итератор each в Ruby

def my_select! col, &block
   col.each {|x| col.delete(x) if block.call(x) == false}
   col
end
p my_select!([1, 3, 5, 7]) {|x| x.even?}

Данный код выводит [3, 7] Хотя пример, в котором присутствуют четные числа, возвращает ожидаемый результат

def my_select! col, &block
   col.each {|x| col.delete(x) if block.call(x) == false}
   col
end
p my_select!([*1..10]) {|x| x.even?}

[2, 4, 6, 8, 10]

Можете объяснить?


Ответы (1 шт):

Автор решения: Nakilon

Скорее всего потому, что Array#delete деструктивный, и если пока идешь по массиву через Array#each, удалять из него элементы, "земля уходить из-под ног" будет. Удалили единицу, и на следующей итерации уже проверяем не 3, а сразу 5. Во втором же случае мы пропустили четное число, поэтому баг себя не проявил.

Нужно избегать применения деструктивных методов к массиву, пока мы по нему идем, если это только не является нашей хитрой задумкой с намеренным пропуском после каждого удаления (однако, следует заметить, что delete удаляет все вхождения сразу, так что если единиц будет несколько подряд, то мы пропустим не одно следующее значение, а целую череду).

→ Ссылка