2016-06-27 7 views
1

In den folgenden Codezeilen unterscheidet sich das Ergebnis, das ich erwartete, von dem tatsächlichen Ergebnis. Kann mir jemand helfen, warum zu verstehen?Ruby hängt an Arrays

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

Sie anhängt und die gleiche Anordnung zu ändern. –

+0

Warum ist es nicht sequentiell, auch wenn ich an das gleiche Array angehängt bin? (also die erste Schleife, die ich 1,2,3 an Array1 anfüge und dann 4,5,6 anfüge) (ich bin ein Anfänger) – Breezecom

+1

Nein, Sie fügen * hinzu und mutieren * das gleiche Array. Sie fügen es einmal an, wenn es 123 ist. Dann ändern Sie es in 456, was bedeutet, dass die bereits angehängte Datei in 456 geändert wird, und Sie dann erneut anhängen. –

Antwort

4

dies tun, und es wird funktionieren (add .clone für alle Verweise auf temp1):

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"]] 

Grundsätzlich, wenn Sie temp1 in array1 anhängen kommt es durch Bezugnahme anstatt nach Wert. Wann immer temp1 aktualisiert wird, wird der entsprechende angehängte Eintrag in array1 ebenfalls automatisch aktualisiert. Um dieses Verhalten zu verhindern, müssen Sie das Objekt clone/dup vor dem Anhängen an das Array. clone/dup duplizieren Sie das Objekt (also nicht die gleiche Referenz/Objekt-ID) und weist es dann zu.

Für eine detaillierte Erklärung überprüfen Sie this Beitrag.

+0

hab es, danke. – Breezecom

+0

Bin froh, dass es geholfen hat:) –

2

Immer wenn Sie Probleme wie diese haben, ist es lehrreich, einen Code zum Ausdrucken der object_id jedes Objekts von Interesse in jedem der verschiedenen Schritte in der Berechnung hinzuzufügen. Jedes Ruby-Objekt hat eine eindeutige object_id.

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

Versuchen wir es: Die ID kann Object.object_id mit dem Verfahren abgerufen werden. (Ich habe object_id ‚s verkürzt, um ihre letzten drei Ziffern zu erleichtern, um zu sehen, wenn sie sich ändern.)

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 

druckt

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] 

Sie müssen dies sorgfältig studieren.

Um zu verstehen, was vor sich geht, kann es hilfreich sein, sich ein Array als Container vorzustellen. Sie haben den Inhalt eines Containers geändert, aber nicht den Container selbst. array1 ist eine Liste von Containern.

Um Ihren Code arbeiten zu lassen, müssen Sie nur den Container und den Inhalt ändern. Ein einfacher Weg ist zu ersetzen:

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

mit

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 

druckt

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

Sehr hilfreich danke. – Breezecom