Как изменение массива во время итерации работает в Ruby? - PullRequest
0 голосов
/ 14 февраля 2020

Учитывая массив в Ruby:

numbers = [1, 2, 3, 4]

Я запутался в результате того, что происходит при изменении массива при итерации по массиву:

numbers.each do |number|
  p number
  numbers.shift(1)
end

Вывод, который я получаю при запуске кода, равен 1 и 3. 1 имеет смысл для первого l oop, но я не могу понять, почему программа возвращает 3.

Я изменил исходный код, чтобы я мог видеть, что происходит на каждом шаге пути, и включил метки ha sh «----», чтобы знать, когда закончится работа каждого l oop:

numbers = [1, 2, 3, 4]
numbers.each_with_index do |number, index|
  p "Array is #{numbers} and index is #{index}"
  p "Number is #{number}"
  numbers.shift(1)
  p "The Array after shift is now #{numbers}, number is #{number}, and the index is now #{index}"
  p "----"
end

Через первый l oop сдвиг успешно удаляет 1 из исходного массива, и массив становится [2,3,4], а «число» равно 1. Но на втором l * Через 1025 * вместо «число», возвращающее 2, возвращается 3.

Единственный способ, который, на мой взгляд, имеет смысл, заключается в том, что сам индекс должен определять, какой элемент удалить из массива. Когда индекс равен 0, он удаляет элемент массива с индексом 0 из массива, а когда индекс равен 1, он удаляет элемент массива с индексом 1 из обновленного массива. Затем l oop останавливается, когда индекс равен 2, поскольку в массиве больше нет элемента с индексом 2.

Этот вопрос является частью курса Launch School. Я не могу понять, почему код возвращает то, что он делает. Я также пытался вставить binding.pry как до, так и после вызова numbers.shift(1), но, похоже, он мне ничего не прояснил.

Ответы [ 2 ]

2 голосов
/ 14 февраля 2020
numbers = [1, 2, 3, 4]

Хорошо, здесь мы go с

numbers.each do |number|
  # do stuff
end

Первый номер

p number # 1, we are on the first element of [1, 2, 3, 4]
numbers.shift(1) # numbers is now [2, 3, 4]

Второй номер

p number # 3, we are on the second element of [2, 3, 4]
numbers.shift(1) # numbers is now [3, 4]

Третий номер - подождите, третьего элемента [3, 4] нет, все готово.

1 голос
/ 14 февраля 2020

не смотрите на это как на значения, а скорее как на адрес. Перечислитель (или Итерация) следует за следующим адресом, указанным текущим.

1st loop:
  1. number points to the first address (with value 1)
  2. shifting array making the current 2nd address the 1st, therefore the value 2 is now on the 1st address.

2nd loop:
  1. number points to the 2nd address (with value 3)
  2. shifting array making the current 2nd address the 1st

3rd loop:
  ※same logic until 'StopIteration' is met

Что касается 'shift', он просто удалит 1-й элемент без чрезмерного мышления.

ссылка: https://apidock.com/ruby/Enumerator/next_values

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