如何在 Ruby 中复制哈希值?

发布于 2024-10-02 16:37:10 字数 432 浏览 1 评论 0原文

我承认我有点像 ruby​​ 新手(现在正在编写 rake 脚本)。在大多数语言中,复制构造函数很容易找到。找了半个小时没有在ruby中找到。我想创建哈希的副本,以便可以修改它而不影响原始实例。

一些预期的方法无法按预期工作:

h0 = {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1=Hash.new(h0)
h2=h1.to_hash

与此同时,我采用了这种不优雅的解决方法

def copyhash(inputhash)
  h = Hash.new
  inputhash.each do |pair|
    h.store(pair[0], pair[1])
  end
  return h
end

I'll admit that I'm a bit of a ruby newbie (writing rake scripts, now). In most languages, copy constructors are easy to find. Half an hour of searching didn't find it in ruby. I want to create a copy of the hash so that I can modify it without affecting the original instance.

Some expected methods that don't work as intended:

h0 = {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1=Hash.new(h0)
h2=h1.to_hash

In the meantime, I've resorted to this inelegant workaround

def copyhash(inputhash)
  h = Hash.new
  inputhash.each do |pair|
    h.store(pair[0], pair[1])
  end
  return h
end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

秋日私语 2024-10-09 16:37:11

由于 Ruby 有一百万种方法可以做到这一点,因此这是使用 Enumerable 的另一种方法:

h0 = {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1 = h0.inject({}) do |new, (name, value)| 
    new[name] = value;
    new 
end

Since Ruby has a million ways to do it, here's another way using Enumerable:

h0 = {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
h1 = h0.inject({}) do |new, (name, value)| 
    new[name] = value;
    new 
end
贵在坚持 2024-10-09 16:37:11

您可以使用下面的方法来深度复制 Hash 对象。

deeply_copied_hash = Marshal.load(Marshal.dump(original_hash))

you can use below to deep copy Hash objects.

deeply_copied_hash = Marshal.load(Marshal.dump(original_hash))
梦里的微风 2024-10-09 16:37:11

对我有用的 Deep_Copy 的替代方法。

h1 = {:a => 'foo'} 
h2 = Hash[h1.to_a]

这产生了一个 deep_copy,因为 h2 是使用 h1 的数组表示形式而不是 h1 的引用形成的。

Alternative way to Deep_Copy that worked for me.

h1 = {:a => 'foo'} 
h2 = Hash[h1.to_a]

This produced a deep_copy since h2 is formed using an array representation of h1 rather than h1's references.

莫相离 2024-10-09 16:37:10

clone 方法是 Ruby 的标准构建方法- 进行浅拷贝的方式:

h0 = {"John" => "Adams", "Thomas" => "Jefferson"}
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}
h1 = h0.clone
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}
h1["John"] = "Smith"
# => "Smith"
h1
# => {"John"=>"Smith", "Thomas"=>"Jefferson"}
h0
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}

请注意,该行为可能会被覆盖:

此方法可能具有特定于类的行为。如果是这样,该行为将记录在类的 #initialize_copy 方法下。

The clone method is Ruby's standard, built-in way to do a shallow-copy:

h0 = {"John" => "Adams", "Thomas" => "Jefferson"}
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}
h1 = h0.clone
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}
h1["John"] = "Smith"
# => "Smith"
h1
# => {"John"=>"Smith", "Thomas"=>"Jefferson"}
h0
# => {"John"=>"Adams", "Thomas"=>"Jefferson"}

Note that the behavior may be overridden:

This method may have class-specific behavior. If so, that behavior will be documented under the #initialize_copy method of the class.

秋风の叶未落 2024-10-09 16:37:10

正如其他人指出的那样,clone 会做到这一点。请注意,哈希的克隆会生成浅表副本。也就是说:

h1 = {:a => 'foo'} 
h2 = h1.clone
h1[:a] << 'bar'
p h2                # => {:a=>"foobar"}

发生的情况是散列的引用被复制,但引用引用的对象没有被复制。

如果您想要深层复制,那么:

def deep_copy(o)
  Marshal.load(Marshal.dump(o))
end

h1 = {:a => 'foo'}
h2 = deep_copy(h1)
h1[:a] << 'bar'
p h2                # => {:a=>"foo"}

deep_copy 适用于任何可以编组的对象。大多数内置数据类型(数组、散列、字符串等)都可以进行编组。

编组是Ruby对序列化的名称。通过编组,对象及其引用的对象被转换为一系列字节;然后这些字节被用来创建另一个像原始对象一样的对象。

As others have pointed out, clone will do it. Be aware that clone of a hash makes a shallow copy. That is to say:

h1 = {:a => 'foo'} 
h2 = h1.clone
h1[:a] << 'bar'
p h2                # => {:a=>"foobar"}

What's happening is that the hash's references are being copied, but not the objects that the references refer to.

If you want a deep copy then:

def deep_copy(o)
  Marshal.load(Marshal.dump(o))
end

h1 = {:a => 'foo'}
h2 = deep_copy(h1)
h1[:a] << 'bar'
p h2                # => {:a=>"foo"}

deep_copy works for any object that can be marshalled. Most built-in data types (Array, Hash, String, &c.) can be marshalled.

Marshalling is Ruby's name for serialization. With marshalling, the object--with the objects it refers to--is converted to a series of bytes; those bytes are then used to create another object like the original.

倾听心声的旋律 2024-10-09 16:37:10

如果您使用 Rails,您可以执行以下操作:

h1 = h0.deep_dup

http://apidock.com/rails/Hash/deep_dup

If you're using Rails you can do:

h1 = h0.deep_dup

http://apidock.com/rails/Hash/deep_dup

北方。的韩爷 2024-10-09 16:37:10

Hash 可以从现有的哈希值创建新的哈希值:

irb(main):009:0> h1 = {1 => 2}
=> {1=>2}
irb(main):010:0> h2 = Hash[h1]
=> {1=>2}
irb(main):011:0> h1.object_id
=> 2150233660
irb(main):012:0> h2.object_id
=> 2150205060

Hash can create a new hash from an existing hash:

irb(main):009:0> h1 = {1 => 2}
=> {1=>2}
irb(main):010:0> h2 = Hash[h1]
=> {1=>2}
irb(main):011:0> h1.object_id
=> 2150233660
irb(main):012:0> h2.object_id
=> 2150205060
断舍离 2024-10-09 16:37:10

正如 Marshal 文档的安全注意事项部分中提到的,

如果您需要反序列化不受信任的数据,请使用 JSON 或其他
只能加载简单的“原始”序列化格式
String、Array、Hash 等类型

以下是如何在 Ruby 中使用 JSON 进行克隆的示例:

require "json"

original = {"John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
cloned = JSON.parse(JSON.generate(original))

# Modify original hash
original["John"] << ' Sandler'
p original 
#=> {"John"=>"Adams Sandler", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}

# cloned remains intact as it was deep copied
p cloned  
#=> {"John"=>"Adams", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}

As mentioned in Security Considerations section of Marshal documentation,

If you need to deserialize untrusted data, use JSON or another
serialization format that is only able to load simple, ‘primitive’
types such as String, Array, Hash, etc.

Here is an example on how to do cloning using JSON in Ruby:

require "json"

original = {"John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
cloned = JSON.parse(JSON.generate(original))

# Modify original hash
original["John"] << ' Sandler'
p original 
#=> {"John"=>"Adams Sandler", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}

# cloned remains intact as it was deep copied
p cloned  
#=> {"John"=>"Adams", "Thomas"=>"Jefferson", "Johny"=>"Appleseed"}
残月升风 2024-10-09 16:37:10

我也是 Ruby 的新手,在复制哈希时也遇到了类似的问题。使用以下内容。我不知道这种方法的速度。

copy_of_original_hash = Hash.new.merge(original_hash)

I am also a newbie to Ruby and I faced similar issues in duplicating a hash. Use the following. I've got no idea about the speed of this method.

copy_of_original_hash = Hash.new.merge(original_hash)
束缚m 2024-10-09 16:37:10

使用 Object#clone:(

h1 = h0.clone

令人困惑的是, clone 的文档说 initialize_copy 是重写此方法的方法,但 Hash 中该方法的链接会引导您replace 相反...)

Use Object#clone:

h1 = h0.clone

(Confusingly, the documentation for clone says that initialize_copy is the way to override this, but the link for that method in Hash directs you to replace instead...)

往事风中埋 2024-10-09 16:37:10

由于标准克隆方法保留了冻结状态,因此如果您希望新对象与原始对象略有不同(如果您喜欢无状态编程),则它不适合基于原始对象创建新的不可变对象。

Since standard cloning method preserves the frozen state, it is not suitable for creating new immutable objects basing on the original object, if you would like the new objects be slightly different than the original (if you like stateless programming).

美羊羊 2024-10-09 16:37:10

克隆速度很慢。为了提高性能,可能应该从空白散列和合并开始。不包括嵌套哈希的情况...

require 'benchmark'

def bench  Benchmark.bm do |b|    
    test = {'a' => 1, 'b' => 2, 'c' => 3, 4 => 'd'}
    b.report 'clone' do
      1_000_000.times do |i|
        h = test.clone
        h['new'] = 5
      end
    end
    b.report 'merge' do
      1_000_000.times do |i|
        h = {}
        h['new'] = 5
        h.merge! test
      end
    end
    b.report 'inject' do
      1_000_000.times do |i|
        h = test.inject({}) do |n, (k, v)|
          n[k] = v;
          n
        end
        h['new'] = 5
      end
    end
  end
end
  bench  user      system      total        ( real)
  clone  1.960000   0.080000    2.040000    (  2.029604)
  merge  1.690000   0.080000    1.770000    (  1.767828)
  inject 3.120000   0.030000    3.150000    (  3.152627)
  

Clone is slow. For performance should probably start with blank hash and merge. Doesn't cover case of nested hashes...

require 'benchmark'

def bench  Benchmark.bm do |b|    
    test = {'a' => 1, 'b' => 2, 'c' => 3, 4 => 'd'}
    b.report 'clone' do
      1_000_000.times do |i|
        h = test.clone
        h['new'] = 5
      end
    end
    b.report 'merge' do
      1_000_000.times do |i|
        h = {}
        h['new'] = 5
        h.merge! test
      end
    end
    b.report 'inject' do
      1_000_000.times do |i|
        h = test.inject({}) do |n, (k, v)|
          n[k] = v;
          n
        end
        h['new'] = 5
      end
    end
  end
end
  bench  user      system      total        ( real)
  clone  1.960000   0.080000    2.040000    (  2.029604)
  merge  1.690000   0.080000    1.770000    (  1.767828)
  inject 3.120000   0.030000    3.150000    (  3.152627)
  
九歌凝 2024-10-09 16:37:10

这是一个特殊情况,但如果您从想要获取并复制的预定义哈希开始,您可以创建一个返回哈希的方法:

def johns 
    {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
end

h1 = johns

我遇到的特殊情况是我有一个 JSON 集合- 架构哈希,其中一些哈希是建立在其他哈希之上的。我最初将它们定义为类变量并遇到了这个复制问题。

This is a special case, but if you're starting with a predefined hash that you want to grab and make a copy of, you can create a method that returns a hash:

def johns 
    {  "John"=>"Adams","Thomas"=>"Jefferson","Johny"=>"Appleseed"}
end

h1 = johns

The particular scenario that I had was I had a collection of JSON-schema hashes where some hashes built off others. I was initially defining them as class variables and ran into this copy issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文