Ruby dup/clone 递归

Posted

技术标签:

【中文标题】Ruby dup/clone 递归【英文标题】:Ruby dup/clone recursively 【发布时间】:2012-02-01 09:31:22 【问题描述】:

我有一个像这样的哈希:

h = 'name' => 'sayuj', 
     'age' => 22, 
     'project' => 'project_name' => 'abc', 
                   'duration' => 'prq'

我需要这个哈希的副本,更改不应影响原始哈希。

当我尝试时,

d = h.dup # or d = h.clone
d['name'] = 'sayuj1'
d['project']['duration'] = 'xyz'

p d #=> "name"=>"sayuj1", "project"=>"duration"=>"xyz", "project_name"=>"abc", "age"=>22
p h #=> "name"=>"sayuj", "project"=>"duration"=>"xyz", "project_name"=>"abc", "age"=>22

在这里您可以看到 project['duration'] 在原始哈希中发生了更改,因为 project 是另一个哈希对象。

我希望哈希是 dupedcloned 递归。我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

这是在 Ruby 中制作深拷贝的方法

d = Marshal.load( Marshal.dump(h) )

【讨论】:

这会创建h 引用的所有对象的完整副本。这可能正是 Sayuj 对简单字符串散列所需要的。对于更复杂的对象,这可能不再需要了。一旦可以覆盖Hash#dup 方法以递归地复制values 中的所有哈希值。但这需要针对每种对象类型进行扩展。 @HolgerJust:是的,这就是为什么它被称为“深拷贝”:-) 当然。我只是想提一下,它可能比 OP 的预期做得更多(尽管它可能还不错):) 所以它只是为了将来参考。 请注意,当有默认 proc 时,这将不起作用(例如 h = Hash.new |h,k| h[k] = 1【参考方案2】:

如果你在 Rails 中:Hash.deep_dup

【讨论】:

【参考方案3】:

如果Marchal #dump/load 对不起作用,对于rails 有一个Hash 的方法#deep_dup,所以你可以:

h = 'name' => 'sayuj', 
 'age' => 22, 
 'project' => 'project_name' => 'abc', 
               'duration' => 'prq'

h1 = h.deep_dup

【讨论】:

方法应该是h.deep_dup而不是h.deep.dup deep_dup 方法会将一个类变成匿名类,不推荐。 @TianChen 例子? 看这个例子:class Abc; endh = 'class' => Abc h1 = h.deep_dup # => => "class"=>#<Class:0x0000000abe50a0>【参考方案4】:

这是一个相当老的问题的答案,但我在实现类似的东西时偶然发现了它,我想我会加入一个更有效的方法。

对于像上面这样简单的两级深度哈希,你也可以这样做:

d = h.inject() |copy, (key, value)| 
    copy[key] = value.dup rescue value; copy

我对包含 4k 个元素的散列进行了测试,每个元素为几百字节,它比 Marshal.dump/load 快 50%

当然,它并不完整,因为如果你有一个散列,例如“project_name”字段的值,它就不起作用,但是对于一个简单的 2 级散列,它工作得很好/更快。

【讨论】:

【参考方案5】:

另一种选择是使用处理数组、哈希、结构并且可扩展到用户定义的类的 full_dup gem(完全公开:我是该 gem 的作者)。

使用方法:

require 'full_dup'
# Other code omitted ...
d = h.full_dup

另请注意,full_dup 处理复杂的数据关系,包括循环或递归。

【讨论】:

以上是关于Ruby dup/clone 递归的主要内容,如果未能解决你的问题,请参考以下文章

在 Ruby 类上定义哪种方法来为其实例提供 dup / clone?

这个 ruby​​ 代码算作递归函数吗?

从分层数组Ruby生成平面数组的递归函数[关闭]

在Ruby中递归地展平数组[重复]

ruby 递归符号化键

ruby 堆栈输入递归