2015-04-02 1 views
2

я столкнулся с какой-то непредвиденное поведение Руби массивов:Итерация по конкатенированному массиву изменяет элементы в исходных массивах. Зачем?

array1 = ["a"] 
array2 = ["b"] 
array3 = array1 + array2 

puts "array1 before array3.map!: #{array1}" 
puts "array2 before array3.map!: #{array2}" 
puts "array3 before array3.map!: #{array3}" 

array3.map! { |item| item << "_modified" } 

puts "array1 after array3.map!: #{array1}" 
puts "array2 after array3.map!: #{array2}" 
puts "array3 after array3.map!: #{array3}" 

Терминальные выходы:

array1 before array3.map!: ["a"] 
array2 before array3.map!: ["b"] 
array3 before array3.map!: ["a", "b"] 
array1 after array3.map!: ["a_modified"]    #Unexpected 
array2 after array3.map!: ["b_modified"]    #Unexpected 
array3 after array3.map!: ["a_modified", "b_modified"] #Expected 

Первый вопрос: Почему пункты в array1 и массив2 разные, несмотря на только итерация array3? Объединение двух массивов возвращает новый массив, так почему же существуют затяжные эффекты для array1 и array2?

Второй вопрос: Как я могу изменить элементы массива 3 путем итерации без изменения элементов array1 или array2?

Третий вопрос: Когда .map и .each используются вместо .map !, выход идентичен. Таким образом, кажется, что .each и .map меняют элементы в массиве. Почему это происходит?

+0

После определения трех массивов я получил: 'array1.map (&: object_id) # => [70229175091960]; array2.map (&: object_id) # => [70229175065880]; array3.map (&: object_id) # => [70229175091960, 70229175065880] '. Это помогает? –

ответ

5

array1 и array2 не изменяются. Строки "a" и "b" изменены.

Посмотрите на это следующим образом:

string = "a" 
array = [string, string, string] # ["a", "a", "a"] 
string << "b" 
array # ["ab", "ab", "ab"] 

Массив не изменился. Это все еще [string, string, string]. Но string отличается.

EDIT Чтобы уточнить и повторить комментарии, вы не изменили массив. Который изменяет размер массива:

array3.each_index { |index| array3[index] = item + "_modified" } 

при замене каждого элемента на другой. Когда вы выполните это, array1 и array2 напечатайте без изменений - их элементы выбиты из array3 и заменены чем-то другим. То, что вы сделали:

array3.map! { |item| item << "_modified" } 

прилагается "_modifier" к каждому пункту (без Мессинг с его идентичностью), то map! заменить каждый элемент в array3с тем же элементом. Таким образом, array3 все еще имел те же элементы, что и array1, и array2, и любое изменение в одном отразилось в другом.

+0

Я думал, что изменение элемента в массиве - это именно то, что означает изменение массива. – jro

+0

ОК, скажем, у вас есть кукольный дом с 3 куклами. Вы окунаете одну из кукол в синюю краску. Изменен ли дом куклы? У нее все еще есть те же три куклы, что и раньше. Конечно, это выглядит по-другому (так же, как 'array1' выглядит по-другому, когда вы распечатываете его), но имеет то же самое содержимое, что и раньше. – Amadan

+0

Пусть array = [1,2,3]. Если array.map! {| val | i * 2}, то он сказал, что массив был изменен с тех пор, массив [2,4,6]. – jro