2011-05-09 57 views
6

我想在我需要時使用默認值重置my ary。但是我無法弄清楚當ary的值發生變化時如何更改默認值。如何在空數組的散列上使用默認值?

> default = {"a"=>[], "b"=>[], "c"=>[]} 
=> {"a"=>[], "b"=>[], "c"=>[]} 

> ary = default.clone 
=> {"a"=>[], "b"=>[], "c"=>[]} 

> ary["a"] << "foo" 
=> ["foo"] 

> default 
=> {"a"=>["foo"], "b"=>[], "c"=>[]} 
+0

我能問你爲什麼這麼做嗎? – 2011-05-09 23:51:42

+0

它基本上是分配給不同狀態的統計數據列表,狀態是鍵。我週期性地想重置統計列表,但保持所有狀態不變。 – 2011-05-10 01:26:02

回答

7

您在這裏發現那是什麼Hash#clone只做一個淺克隆,即只進行自我複製,但不是被其內引用的對象。

有許多的「深度克隆」的寶石,解決特定問題,或者你可以寫你自己去解決它:

class Hash 
    def deep_clone 
    Hash[collect { |k,v| [ k, v.respond_to?(:deep_clone) : v.deep_clone : v ] }] 
    end 
end 

class Array 
    def deep_clone 
    collect { |v| v.respond_to?(:deep_clone) : v.deep_clone : v } 
    end 
end 

這將讓你克隆任意Hash和Array對象的要求。

+0

感謝您的幫助,但我得到有關respond_to?(:clone)語句的語法錯誤。 – 2011-05-09 20:56:45

+0

在調用它之前,它只是檢查所討論的對象是否支持'deep_clone'方法,因爲您無法克隆諸如數字,「true」和「false」之類的內容。在實踐中你需要深入克隆的唯一東西就是容器類型的對象。 – tadman 2011-05-09 20:58:19

3

clone和dup都會創建對象的淺表副本,這會導致此行爲。我不知道,實現了深拷貝正確的方法是什麼,但不是:

ary = default.clone 

嘗試:

ary = Marshal.load(Marshal.dump(default)) 

這是從現場2.3.8環境採取的紅寶石1.8。 7

+0

元帥無法處理你所投的一切,所以要小心。另外,這必須是執行這種事情的最昂貴的方法之一。 – tadman 2011-05-09 20:57:40

+0

這就是爲什麼我說我不確定什麼是正確的方法。我喜歡你的建議作爲一個更具體的案例解決方案,所以它得到我的upvote;) – 2011-05-09 21:13:33

2

clone只做淺拷貝,這就是爲什麼克隆你的哈希仍然保持一切指向相同的嵌套數組。

您可以通過傾倒,然後加載在對象的值通過Marshal類避免這種情況:

> default = {"a" => [], "b" => [], "c" => []} 
=> {"a"=>[], "b"=>[], "c"=>[]} 
> ary = Marshal.load(Marshal.dump(default)) 
=> {"a"=>[], "b"=>[], "c"=>[]} 
> ary["a"] << "foo" 
=> ["foo"] 
> default 
=> {"a"=>[], "b"=>[], "c"=>[]} 
2
class Object 
    def deep_clone 
    Marshal::load(Marshal.dump(self)) 
    end 
end 

default = {"a"=>[], "b"=>[], "c"=>[]} 
ary = default.deep_clone 
ary["a"] << "foo" 
default {"a"=>[], "b"=>[], "c"=>[]} 
+0

奇怪的是,你會使用'::'表示法的一種方法和'.'爲另一個,但總體上+1。 – Phrogz 2011-05-09 22:59:15

+0

你能用'::'調用方法總是讓我感到奇怪和困惑。 – tadman 2011-05-10 00:26:26

2

做到這一點的方法如下:

ary = Marshal.load(Marshal.dump(default)) 
2

根據你想要做什麼,更簡單的替代方法來編寫深度克隆方法可能是編寫一個方法,每次調用它時都會創建一個新的默認數組:

def default 
    {"a"=>[], "b"=>[], "c"=>[]} 
end 

ary = default #=> {"a"=>[], "b"=>[], "c"=>[]} 

ary["a"] << "foo" #=> {"a"=>["foo"], "b"=>[], "c"=>[]} 

default #=> {"a"=>[], "b"=>[], "c"=>[]} 

當然,如果默認散列的內容在程序過程中發生變化,這將不起作用,您將不得不查看克隆或編組技術,但如果內容已修復,是一個更直接的解決方案。

相關問題