Почему ул.next! в Enumerable#map заполнить массив одинаковыми элементами?

Enumerable#map создает массив с возвращаемыми значениями в блоке после его получения.

В таком случае скажите:

v = 'a'
26.times.map { |i| v.ord.+(i).chr }

# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

Но почему следующие коды заполняют массив одинаковыми элементами?

v = '`'
26.times.map { v.next! }

# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
v = '`'
Array.new(26) { v.next! }

# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]

Разве все они не должны иметь элементы от a до z?

Опять же, это работает:

v = '`'
Array.new(26) { v = v.succ }

# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

На самом деле я пытаюсь сделать:

v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v = v.succ) }

# => {:a=>"?", :b=>"?", :c=>"?", :d=>"?", :e=>"?", :f=>"?", :g=>"?", :h=>"?", :i=>"?", :j=>"?", :k=>"?", :l=>"?", :m=>"?", :n=>"?", :o=>"?", :p=>"?", :q=>"?", :r=>"?", :s=>"?", :t=>"?", :u=>"?", :v=>"?", :w=>"?", :x=>"?", :y=>"?", :z=>"?"}

Но вместо этого я получаю все z при использовании succ! / next!

v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v.succ!) }

# => {:a=>"?", :b=>"?", :c=>"?", :d=>"?", :e=>"?", :f=>"?", :g=>"?", :h=>"?", :i=>"?", :j=>"?", :k=>"?", :l=>"?", :m=>"?", :n=>"?", :o=>"?", :p=>"?", :q=>"?", :r=>"?", :s=>"?", :t=>"?", :u=>"?", :v=>"?", :w=>"?", :x=>"?", :y=>"?", :z=>"?"}

За исключением того, что succ! / next! не изменяет расположение памяти и object_id, разве v.succ! и v = v.succ не совпадают?

Что касается вашей проблемы: (:a..:z).zip('?'..'?').to_h кажется намного проще.

Stefan 13.07.2019 13:35

Да, это круто! Но почему метод взрыва не работает, пока работает оператор присваивания?

S.Goswami 13.07.2019 13:38

Это работает, но у вас есть массив, ссылающийся на один и тот же объект 26 раз, вместо массива с 26 разными объектами. Смотри ниже.

mrzasa 13.07.2019 13:42
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
2
3
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Когда вы вызываете next! или succ! для переменной str, объект, назначенный этой переменной, изменяется, и возвращается ссылка на этот объект. Если str = 'a' и вы позвоните str.next! 26 раз, str станет z. Каждый раз, когда вызывается next!, возвращается ссылка на один и тот же объект. В результате вы получите массив из 26 ссылок на один и тот же объект. Вот почему все элементы в массиве одинаковы.

Вы можете проверить это, проверив object_id элементов массива:

pry(main)> str = 'a'
'a'
pry(main)> array = 3.times.map{ str.next!}
=> ["d", "d", "d"]
pry(main)> array.map(&:object_id)
=> [47056742362940, 47056742362940, 47056742362940]
pry(main)> array.map(&:object_id).uniq
=> [47056742362940]

При редактировании str обновляются все элементы массива:

[39] pry(main)> str << "b"
=> "db"
[40] pry(main)> array
=> ["db", "db", "db"]
[41] pry(main)> str.replace
str.replace
[41] pry(main)> str.replace('a')
=> "a"
[42] pry(main)> array
=> ["a", "a", "a"]

Если вы хотите иметь массив со всем алфавитом, вам нужно скопировать строку после изменения текущей буквы, см. ниже:

[25] pry(main)> str = 'a'
=> "a"
[26] pry(main)> 25.times.map{ str.next!.dup} 
=> ["b",
 "c",
 "d",
 "e",
 "f",
 "g",
 "h",
 "i",
 "j",
 "k",
 "l",
 "m",
 "n",
 "o",
 "p",
 "q",
 "r",
 "s",
 "t",
 "u",
 "w",
 "x",
 "y",
 "z"]

Вы также можете использовать диапазон:

[32] pry(main)> ('a'..'z').to_a
=> ["a",
 "b",
 "c",
 "d",
 "e",
 "f",
...

О, это потрясающе! Итак, в этом случае, когда вы назначаете массив, чтобы сказать a, тогда, если вы напишете z.replace('hello'), весь массив a заполнится «привет»! ...Похоже на a.fill('hello')

S.Goswami 13.07.2019 13:52

Я обновил свой ответ, чтобы покрыть изменение объекта.

mrzasa 13.07.2019 15:00

Другие вопросы по теме