【问题标题】:How can I marshal a hash with arrays?如何用数组编组哈希?
【发布时间】:2010-03-31 11:15:52
【问题描述】:

我应该如何编组数组的哈希? 下面的代码只打印{}

s = Hash.new
s.default = Array.new
s[0] << "Tigger"
s[7] << "Ruth"
s[7] << "Puuh"
data = Marshal.dump(s)
ls = Marshal.restore( data )
p ls

如果哈希不包含数组,它会被正确恢复。

【问题讨论】:

    标签: ruby serialization


    【解决方案1】:
    s = Hash.new
    s.default = Array.new
    s[0] << "Tigger"
    s[7] << "Ruth"
    s[7] << "Puuh"
    

    此代码更改默认值 3 次(这可能是转储中显示的内容),但它不会在哈希中存储任何内容。试试“puts s[8]”,它会返回 [["Tigger"], ["Ruth"], ["Puuh"]]。

    Hash.default_proc 会做你想做的事

    s = Hash.new{|hash,key| hash[key]=[] }
    

    但是你不能编组一个触发。这将起作用:

    s = Hash.new
    s.default = Array.new
    s[0] += ["Tigger"]
    s[7] += ["Ruth"]
    s[7] += ["Puuh"]
    

    之所以有效,是因为 []+=["Tigger"] 创建了一个 new 数组。 另一种方法是创建更少的数组:

    s = Hash.new
    (s[0] ||= []) << "Tigger"
    (s[7] ||= []) << "Ruth"
    (s[7] ||= []) << "Puuh"
    

    仅当键不存在(nil)时创建一个新数组。

    【讨论】:

    【解决方案2】:

    你可以在初始化 Hash.new 的时候创建你的哈希结构来避免这样的麻烦

    h = Hash.new{ |a,b| a[b] = [] }
    h[:my_key] << "my value"
    

    【讨论】:

    • 很好的答案,这比我的append_to_hash 好得多。
    • 不幸的是,它在编组时给了我一个“无法使用默认 proc 转储哈希”错误。我猜那是因为 [] 的重新定义。
    • 你需要s.default = Array.new 否则你会得到那个错误。
    • 好的,这可以正常工作,但在恢复时再次给我{}。
    【解决方案3】:

    您可能会被 Hash.default 的工作原理误导。

    Marshal.dump 之前,打印数据结构。它是{}。那是因为您将每个字符串连接到 nil 中,而不是连接到空数组中。下面的代码说明并解决了您的问题。

    s = Hash.new
    s.default = Array.new
    s[0] = []
    s[0] << "Tigger"
    s[7] = []
    s[7] << "Ruth"
    s[7] << "Puuh"
    p s
    data = Marshal.dump(s)
    ls = Marshal.restore( data )
    p ls
    

    返回:

    {0=>["Tigger"], 7=>["Ruth", "Puuh"]}
    {0=>["Tigger"], 7=>["Ruth", "Puuh"]}
    

    编辑:

    我在哈希中插入了很多数据

    所以也许一些帮助代码会使插入过程更顺畅:

    def append_to_hash(hash, position, obj)
      hash[position] = [] unless hash[position]
      hash[position] << obj
    end
    
    s = Hash.new
    append_to_hash(s, 0, "Tigger")
    append_to_hash(s, 7, "Ruth")
    append_to_hash(s, 7, "Puuh")
    s.default = Array.new // this is only for reading
    p s
    data = Marshal.dump(s)
    ls = Marshal.restore( data )
    p ls
    

    【讨论】:

    • 打印我的示例中的数据转储会给出 "\004\b}\000[\b\"\vTigger\"\tRuth\"\tPuuh" 所以很明显数据在那里但它不可能使用过。我试图避免插入的特殊子句,因为我在哈希中插入了大量数据。
    • 您可以使用+而不是&lt;&lt;方法追加元素,这样您就不需要初始化每个新元素。
    • 在这里不起作用 - 给出相同的结果。版本是带有 jRuby 1.8.6 的 NetBeans。你能提供一个运行的例子吗?
    • 编辑版适合我。期待更清洁的东西。 ;-)
    【解决方案4】:

    由于您不能在带有 proc 作为默认元素的 Hash 上使用 Marshall.dump,因此您可以使用稍微迂回的方式附加到每个 Array 而不是 &lt;&lt;

    s = Hash.new
    s.default = []
    s[0] += [ "Tigger" ]
    s[7] += [ "Ruth" ]
    s[7] += [ "Pooh" ]
    data = Marshal.dump(s)
    ls = Marshal.restore(data)
    p ls
    

    【讨论】:

      猜你喜欢
      • 2011-04-20
      • 2016-03-30
      • 2012-10-29
      • 2018-03-12
      • 2018-01-28
      • 2015-11-26
      • 2021-11-21
      • 2011-07-26
      相关资源
      最近更新 更多