如何递归地将Ruby哈希表中的符号键转换为字符串

5
假设我有以下哈希表或嵌套哈希表:
h = { :a1 => { :b1 => "c1" },
      :a2 => { :b2 => "c2"},
      :a3 => { :b3 => "c3"} }

我想创建一个方法,它以哈希作为参数,并递归地将所有键(键是符号,例如:a1)转换为字符串(例如"a1")。到目前为止,我已经想出了以下的方法,但它不能正常工作,返回结果为{"a1"=>{:b1=>"c1"}, "a2"=>{:b2=>"c2"}, "a3"=>{:b3=>"c3"}}。:
def stringify_all_keys(hash)
    stringified_hash = {}
    hash.each do |k, v|
        stringified_hash[k.to_s] = v
        if v.class == Hash
            stringify_all_keys(stringified_hash[k.to_s])
        end
    end
    stringified_hash
end

我做错了什么,如何将所有键转换为像这样的字符串:
{"a1"=>{"b1"=>"c1"}, "a2"=>{"b2"=>"c2"}, "a3"=>{"b3"=>"c3"}}

4
快速、简单粗暴且十分低效的方法:JSON.parse(h.to_json) - Jake H
太棒了!!!成功了!非常感谢。 :) - dhrubo_moy
4个回答

15
如果您已经在使用ActiveSupport或者愿意使用它,那么deep_stringify_keys就是你要找的。
hash = { person: { name: 'Rob', age: '28' } }

hash.deep_stringify_keys
# => {"person"=>{"name"=>"Rob", "age"=>"28"}}

如果你正在使用带有ActiveSupport的堆栈,那么这比我的答案更可取。需要注意的是,在哈希表中任何数组内部的符号也将被转换为字符串。 - Jake H
嗯,不会的:{ 'foo' => ['a', 'b'] }.deep_symbolize_keys #=> {:foo=>["a", "b"]}deep_symbolize_keys 内部使用了 deep_transform_keys,顾名思义只作用于哈希表的键,而不是值。 - Michael Kohl
我改口了。话虽如此,符号数组键将被转换为字符串数组,这不是我所说的,但与问题实现的具体细节有所不同。 编辑:实际上,我撤回之前的说法,数组键只是直接转换为字符串: { [:a,:z] => [:b,:c] }.deep_stringify_keys # {"[:a, :z]"=>[:b, :c]} - Jake H
1
deep_stringify_keys == deep_transform_keys(&:to_s),所以没有什么意外。 - Michael Kohl
1
非常尴尬,我很惊讶,转换只在值方面进行深度操作。在我看来,深度操作意味着无处不传播。抱歉我的无知。 - Jake H

6

如果您的值是基本对象,如字符串、数字等,则可以使用快速且简单的方法:

require 'json'
JSON.parse(JSON.dump(hash))

这种解决方案相对于Michael Kohl的解决方案的优势在于它可以处理DateTime对象(实际上是任何对象)。 - germs12
与Michael Kohl的解决方案相比,这个解决方案的优势在于它可以处理DateTime对象(实际上,任何对象)。 - undefined

3

我没有测试过,但看起来大致正确:

def stringify_all_keys(hash)
  stringified_hash = {}
  hash.each do |k, v|
    stringified_hash[k.to_s] = v.is_a?(Hash) ? stringify_all_keys(v) : v
  end
  stringified_hash
end

0

使用纯Ruby代码,以下代码可帮助您。 您可以将其Monkey Patch到Ruby Hash中,以像这样使用my_hash.deeply_stringfy_keys 但是,我不建议Monkey Batching Ruby。

您可以调整该方法以提供其deeply_strigify_keys!(bang)版本。

如果您想制作一个不递归字符串化的不同方法,或者控制字符串化的级别,请考虑重新编写下面的方法逻辑,以便更好地编写它,并考虑上述其他变体。

def deeply_stringify_keys(hash)
  stringified_hash = {}
  hash.each do |k, v|
    if v.is_a?(Hash)
      stringified_hash[k.to_s] = deeply_stringify_keys(v)
    elsif v.is_a?(Array)
      stringified_hash[k.to_s] = v.map {|i| i.is_a?(Hash)? deeply_stringify_keys(i) : i}
    else
      stringified_hash[k.to_s] = v
    end
  end
  stringified_hash
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接