我想將嵌套散列中的所有值轉換爲與utf8兼容的字符串。我最初認爲這很容易,並且應該可以使用類似deep_apply
的內容,但我無法在快速Google和SO搜索中找到任何此類簡單內容。如何轉換嵌套散列中的所有值?
我不想寫(維護)與Change values in a nested hash相似的方法。是否有一個本地API實現或速記可用於此,還是我必須寫我自己的方法?
我想將嵌套散列中的所有值轉換爲與utf8兼容的字符串。我最初認爲這很容易,並且應該可以使用類似deep_apply
的內容,但我無法在快速Google和SO搜索中找到任何此類簡單內容。如何轉換嵌套散列中的所有值?
我不想寫(維護)與Change values in a nested hash相似的方法。是否有一個本地API實現或速記可用於此,還是我必須寫我自己的方法?
有趣的是學習了「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}}
yourhash.deep_merge(yourhash) {|_,_,v| v.to_s}
合併哈希與自身,檢查值,就可以調用to_s
。
如果您不在rails上使用ruby,則此方法需要文件頂部的require 'active_support/core_ext/hash'
。
顯然,您可以按照您的要求處理deep_merge
內v
的轉換,以滿足您的要求。
在軌控制檯:
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]"}}
嗯,這是很簡單的寫吧 - 那麼,爲什麼不寫你自己的和絕對確保它是如何在各種情況下的行爲;)
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
您可能想檢查所有行爲和轉換是否正確 - 並在必要時進行更改。
我最終實現我自己的方法,那就是絕不完美,但很適合我的使用情況和應易於維護。在這裏張貼供參考的人誰願意嘗試一下
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"]}
尼斯.. !!!我最終從你的例子中獲得了靈感,並實現了我自己的類似但更小的方法,它適用於我的用例。非常感謝。 – Vedanshu