2016-06-27 6 views
1

次のコード行では、私が期待していた結果が実際の結果と異なっています。なぜ誰かが私の理解を助けることができますか?配列に追加するRuby

array1 = [["a", "b", "c"], ["a", "b", "c"]] 
temp1 = ["x", "y", "z"] 
array1 << temp1 

2.times do 
    temp1[0] = gets.chomp  #first loop enter 1 and then 4 
    temp1[1] = gets.chomp  #first loop enter 2 and then 5 
    temp1[2] = gets.chomp  #first loop enter 3 and then 6 
    puts temp1.inspect 
    array1 << temp1 
    puts array1.inspect   
    # Actual result: [["a", "b", "c"], ["a", "b", "c"], ["4", "5", "6"], ["4", "5", "6"], ["4", "5", "6"]]       
    # Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]] 
end 
+1

とあなたは同じ配列を付加し、修正しています。 –

+0

なぜ同じ配列に追加してもシーケンシャルではないのですか? (最初のループは1,2,3をarray1に追加してから4,5,6を追加します)(私は初心者です) – Breezecom

+1

いいえ、あなたは*を追加して*同じ配列に変異を加えています。それが123のときに一度追加します。次にそれを456に変更します。つまり、すでに追加したものが456に変更された後、再度追加します。 –

答えて

4

temp1へのすべての参照に.cloneを追加)これを行うと、それは動作します:

基本的に
array1 = [["a", "b", "c"], ["a", "b", "c"]] 
temp1 = ["x", "y", "z"] 
array1 << temp1.clone 
2.times do 
     temp1[0] = gets.chomp  #first loop enter 1 and then 4 
     temp1[1] = gets.chomp  #first loop enter 2 and then 5 
     temp1[2] = gets.chomp  #first loop enter 3 and then 6 

     puts temp1.inspect 
     array1 << temp1.clone 
     puts array1.inspect 

end 

# Actual result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]] 

# Expected Result: [["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], ["4", "5", "6"]] 

、あなたがarray1temp1を追加するとき、それは参照によってではなく、値によって発生します。したがって、temp1が更新されるたびに、array1の対応する追加エントリも自動的に更新されます。この動作を防止するには、オブジェクトを配列に追加する前にオブジェクトをclone/dupにする必要があります。 clone/dupオブジェクトを複製する(同じ参照/ object_idを持たない)ので、オブジェクトを割り当てます。

詳しい説明については、thisの記事を参照してください。

+0

ありがとうございます。 – Breezecom

+0

助けてくれてうれしいです:) –

2

このような問題が発生した場合は、計算のいくつかのステップのそれぞれで、それぞれの対象オブジェクトのobject_idを印刷するコードを追加することが有益です。各Rubyオブジェクトには固有のobject_idがあります。

{ "a"=>1 }.object_id 
    #=> 70225550848400 

のは、それを試してみましょう:idがメソッドObject.object_idで取得することができます。 (私は彼らが変更されたときにそれが簡単に見ることにするために彼らの最後の3桁にobject_id年代を短縮しました。)あなたは慎重にこれを研究する必要がある

array1 = [["a", "b", "c"], ["a", "b", "c"]] 
puts "1a array1.object_id=#{array1.object_id % 1000}" 
puts "1b array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
puts 
temp1 = ["x", "y", "z"] 
puts "2a temp1.object_id=#{temp1.object_id % 1000}" 
array1 << temp1 
puts "2b array1=#{array1.inspect}" 
puts "2c array1.object_id=#{array1.object_id % 1000}" 
puts "2d array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
puts 
2.times do 
    temp1[0] = gets.chomp 
    temp1[1] = gets.chomp 
    temp1[2] = gets.chomp 
    puts "3a temp1=#{temp1.inspect}" 
    puts "3b temp1.object_id=#{temp1.object_id % 1000}" 
    array1 << temp1 
    puts "3c array1=#{array1.inspect}" 
    puts "3d array1.object_id=#{array1.object_id % 1000}" 
    puts "3e array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
    puts 
end 

プリント

1a array1.object_id=900 
1b array1.map(&:object_id)=[0, 920] 

2a temp1.object_id=480 
2b array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"]] 
2c array1.object_id=900 
2d array1.map(&:object_id)=[0, 920, 480] 

1 
2 
3 
3a temp1=["1", "2", "3"] 
3b temp1.object_id=480 
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["1", "2", "3"], ["1", "2", "3"]] 
3d array1.object_id=900 
3e array1.map(&:object_id)=[0, 920, 480, 480] 

4 
5 
6 
3a temp1=["4", "5", "6"] 
3b temp1.object_id=480 
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["4", "5", "6"], ["4", "5", "6"], 
      ["4", "5", "6"]] 
3d array1.object_id=900 
3e array1.map(&:object_id)=[0, 920, 480, 480, 480] 

を。

何が起こっているのかを理解するには、配列をコンテナと考えると便利です。あなたがしたのは、コンテナの内容を変更することですが、コンテナ自体は変更しませんが、array1はコンテナのリストです。

コードを機能させるには、コンテナーと内容を変更するだけです。一つの簡単な方法は、交換することです:

temp1[0] = gets.chomp 
temp1[1] = gets.chomp 
temp1[2] = gets.chomp 

temp1 = [gets.chomp, gets.chomp, gets.chomp] 

array1 = [["a", "b", "c"], ["a", "b", "c"]] 
puts "1a array1.object_id=#{array1.object_id % 1000}" 
puts "1b array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
puts 
temp1 = ["x", "y", "z"] 
puts "2a temp1.object_id=#{temp1.object_id % 1000}" 
array1 << temp1 
puts "2b array1=#{array1.inspect}" 
puts "2c array1.object_id=#{array1.object_id % 1000}" 
puts "2d array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
puts 
2.times do 
    temp1 = [gets.chomp, gets.chomp, gets.chomp] 
    puts "3a temp1=#{temp1.inspect}" 
    puts "3b temp1.object_id=#{temp1.object_id % 1000}" 
    array1 << temp1 
    puts "3c array1=#{array1.inspect}" 
    puts "3d array1.object_id=#{array1.object_id % 1000}" 
    puts "3e array1.map(&:object_id)=#{array1.map { |e| e.object_id % 1000 } }" 
    puts 
end 

プリント

1a array1.object_id=100 
1b array1.map(&:object_id)=[220, 120] 

2a temp1.object_id=660 
2b array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"]] 
2c array1.object_id=100 
2d array1.map(&:object_id)=[220, 120, 660] 

1 
2 
3 
3a temp1=["1", "2", "3"] 
3b temp1.object_id=800 
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"]] 
3d array1.object_id=100 
3e array1.map(&:object_id)=[220, 120, 660, 800] 

4 
5 
6 
3a temp1=["4", "5", "6"] 
3b temp1.object_id=580 
3c array1=[["a", "b", "c"], ["a", "b", "c"], ["x", "y", "z"], ["1", "2", "3"], 
      ["4", "5", "6"]] 
3d array1.object_id=100 
3e array1.map(&:object_id)=[220, 120, 660, 800, 580] 
+0

ありがとう、ありがとう。 – Breezecom