我想将嵌套哈希中的所有值转换为utf8兼容字符串。我最初认为这很容易,我应该可以使用deep_apply
之类的东西,但是我无法在快速谷歌和搜索中找到任何这么简单的东西。
我不想编写(维护)类似Change values in a nested hash行的方法。是否有本机API实现或可用于此的简写,还是我必须编写自己的方法?
答案 0 :(得分:3)
我最终实现了自己的方法,这种方法并不完美,但对我的用例很有用,并且应该易于维护。在此发布以供任何想要试用的人参考
def deep_apply object, klasses, &blk
if object.is_a? Array
object.map { |obj_ele| deep_apply(obj_ele, klasses, &blk) }
elsif object.is_a? Hash
object.update(object) {|_, value| deep_apply(value, klasses, &blk) }
elsif klasses.any? { |klass| object.is_a? klass }
blk.call(object)
else
object
end
end
用法:
=> pry(main)> deep_apply({a: [1, 2, "sadsad"]}, [String, Integer]) { |v| v.to_s + "asd" }
=> {:a=>["1asd", "2asd", "sadsadasd"]}
答案 1 :(得分:2)
yourhash.deep_merge(yourhash) {|_,_,v| v.to_s}
将哈希值与自身合并,检查值并在其上调用to_s
如果您没有在rails上使用ruby,则此方法在文件顶部需要require 'active_support/core_ext/hash'
。
显然,您可以根据自己的要求处理v
内deep_merge
的转换。
在rails控制台中:
2.3.0 :001 > h1 = { a: true, b: { c: [1, 2, 3] } }
=> {:a=>true, :b=>{:c=>[1, 2, 3]}}
2.3.0 :002 > h1.deep_merge(h1) { |_,_,v| v.to_s}
=> {:a=>"true", :b=>{:c=>"[1, 2, 3]"}}
答案 2 :(得分:2)
有兴趣了解“The F”在答案中采用的deep_merge
方法。这是另一种需要添加一些辅助方法的方法。
首先,辅助方法:
从最常见的回答here (converting-a-nested-hash-into-a-flat-hash):
def flat_hash(h,f=[],g={})
return g.update({ f=>h }) unless h.is_a? Hash
h.each { |k,r| flat_hash(r,f+[k],g) }
g
end
来自名为ruby-bury的Github仓库(此功能是针对Ruby内核提出的,但是rejected)
class Hash
def bury *args
if args.count < 2
raise ArgumentError.new("2 or more arguments required")
elsif args.count == 2
self[args[0]] = args[1]
else
arg = args.shift
self[arg] = {} unless self[arg]
self[arg].bury(*args) unless args.empty?
end
self
end
end
然后将方法捆绑在一起:
def change_all_values(hash, &blk)
# the next line makes the method "pure functional"
# but can be removed otherwise.
hash = Marshal.load(Marshal.dump(hash))
flat_hash(hash).each { |k,v| hash.bury(*(k + [blk.call(v)])) }
hash
end
用法示例:
irb(main):063:0> a = {a: 1, b: { c: 1 } }
=> {:a=>1, :b=>{:c=>1}}
irb(main):064:0> b = change_all_values(a) { |val| val + 1 }
=> {:a=>2, :b=>{:c=>2}}
irb(main):066:0> a
=> {:a=>1, :b=>{:c=>1}}
答案 3 :(得分:1)
嗯,编写它很简单 - 所以为什么不写自己的,并且绝对确定它在所有情况下的表现如何;)
def to_utf8(h)
if h.is_a? String
return h.force_encoding('utf-8')
elsif h.is_a? Symbol
return h.to_s.force_encoding('utf-8').to_sym
elsif h.is_a? Numeric
return h
elsif h.is_a? Array
return h.map { |e| to_utf8(e) }.to_s
else
return h.to_s.force_encoding('utf-8')
end
return hash.to_a.map { |e| result.push(to_utf8(e[0], e[1])) }.to_h
end
您可能想要检查所有行为和转化是否正确 - 并在必要时进行更改。