2014-01-09 22 views
1

我想創建哈希像這樣的數組:循環和附加散列到一個數組

[ 
    {"start"=>1, "end"=>2}, 
    {"start"=>2, "end"=>3}, 
    {"start"=>3, "end"=>4}, 
    {"start"=>4, "end"=>5}, 
    {"start"=>5, "end"=>6} 
] 

當我嘗試此代碼:

foo = 1 
bar = 2 
hash = {} 
array = [] 
5.times do 
    hash['start'] = foo 
    hash['end'] = bar 
    array << hash 
    foo += 1 
    bar += 1 
end 

hash值內array改變而循環和哈希值被添加到它。 array變爲:

[ 
    {"start"=>5, "end"=>6}, 
    {"start"=>5, "end"=>6}, 
    {"start"=>5, "end"=>6}, 
    {"start"=>5, "end"=>6}, 
    {"start"=>5, "end"=>6} 
] 

爲什麼會發生這種情況時:

foo = 1 
array = [] 
5.times do 
    array << foo 
    foo += 1 
end 
array # => [1, 2, 3, 4, 5] 

不會在循環過程中改變內部array數字?

+0

使用'陣列<< hash.dup',而不是'因爲你陣列<< hash'」這裏添加的只是散列引用,而不是散列本身。 –

+1

我會使用'(1..6).each_cons(2).map {| a,b | {start:a,end:b}}' – Stefan

回答

3

這是因爲散列是可變的。如果您有foo = {"start" => 1}foo["start"] += 1,那麼foo仍指向相同的散列,儘管它被修改爲{"start" => 2}。它不會更改參考。如果你在一個數組中有同一個對象的多個副本,並修改其中的一個,那麼所有這些對象都將被修改。

另一方面,數字不可變;如果您有foo = 1,並且執行foo += 1,則foo現在將指向2,這是與1不同的對象。

+0

很好的答案。真的很短,並解釋結果背後的機制。 – swelet

1

用途:代替

array << hash.dup 

array << hash 

,因爲你在這裏僅增加了引用哈希,而不是hashs自己。

2

您可以每次創建一個新的散列。

foo = 1 
array = [] 

5.times do 
    array << { 'start' => foo, 'end' => foo + 1 } 
    foo += 1 
end 
+0

這根本不回答問題。 – sawa

1

你應該改變你的代碼在每次循環創建一個新的哈希:

foo = 1 
bar = 2 
array = [] 
5.times do 
    hash = {} 
    hash['start'] = foo 
    hash['end'] = bar 
    array << hash 
    foo += 1 
    bar += 1 
end 
puts array 

否則,你總是在變化相同的對象,這就是你用相同的哈希值作爲數組元素結束的原因。

由於對主體的快速文學從here採取:

Ruby的變量保存對象的=操作副本 引用引用。另外,一個自我賦值如a + = b實際上是 翻譯成a = a + b。因此,建議您注意 是否在某個操作中實際創建新對象 或修改現有對象。

例如,串< <「另一個」是不是字符串+ =「另一個」 (沒有額外的對象創建)更快,所以你會使用任何 類定義的更新方法(如果那是真的會更好你的意圖),如果它 存在。然而,通知還對「副作用」上指向同一個對象的所有其他變量 :

 a = 'aString' 
     c = a 
     a += ' modified using +=' 
     puts c # -> "aString" 

     a = 'aString' 
     c = a 
     a << ' modified using <<' 
     puts c # -> "aString modified using <<"