Тот факт, что только около половины (5/9) ваших предметов исчезли, является мертвой распродажей, которая устраняет проблему при повторном выполнении коллекции.
Итерация будет обрабатывать индексы 1, 2, 3, 4 и так далее. Если вы удалите индекс 2 во время его обработки, это приведет к смещению всех последующих индексов на один.
Итак, когда вы переходите к индексу 3 в следующей итерации, вы пропустите оригинальный индекс 3, потому что будут сдвинуты вниз к индексу 2.
Другими словами, давайте начнем с более простой пример с двумя соседними элементами для удаления:
index | 0 | 1 | 2 | 3 |
value | 1 | 7 | 7 | 9 |
вы проверяете первый индекс и значение 1
так что вы ничего не делаете. Затем проверьте второй индекс и значение 7
так вы удалите его, давая:
index | 0 | 1 | 2 |
value | 1 | 7 | 9 |
Вы затем проверить третий индекс и значение 9
так что вы ничего не делаете. Вы также дошли до конца, чтобы он остановился.
Итак, вы можете видеть, что вы на самом деле пропустили второй элемент, который хотите удалить, потому что вы перемещали вещи во время итерации. Это не проблема, специфичная для Ruby, и у многих языков такая же проблема.
Как правило, каждая полная пара смежных элементов будет иметь только одну из пары, удаленной, когда элемент сам по себе (за которым не следует другое значение) будет удален. Вот почему только 5/9
вашего 7
s удалены, по одному для каждой из четырех пар и окончательного отдельного.
Правильный путь (в Ruby), чтобы удалить все элементы из одного заданного значения является использование array delete метода:
a.delete(7)
Вы также можете использовать conditional delete для более сложных условий, таких как удаление всех больше 7
:
a.delete_if {|val| val > 7}
И, если вы действительно хотите сделать это вам (как учебное упражнение), вам просто нужно понять, что проблема заключается в том, что вы обрабатываете массив в обратном порядке - когда вы это делаете, изменения за пределами того места, где вы удаляете, могут вызывать проблемы.
Если вы хотите найти способ обработки массива обратным образом, эта проблема не возникнет. К счастью, Ruby имеет такой зверь:
a.to_enum.with_index.reverse_each do |item, index|
Эта линия будет обрабатывать массив таким образом, что делеции не будут влиять на будущие операции. Просто имейте в виду, что удаление во время итерации может быть еще быть проблемой, если структура данных, которую вы обрабатываете, не является простым индексированным массивом.
Я по-прежнему гарантирую, что delete
и delete_if
- это правильный путь, поскольку они уже запечены в Ruby, и поэтому невероятно маловероятно, чтобы были ошибки.
потому что вы удаляете во время цикла – dnit13
@ dnit13, поэтому правильный способ удалить все 7 в массиве? – NamNamNam
http://ruby-doc.org/core-2.2.0/Array.html#method-i-delete – dnit13