[ruby]Hashのキー(key)をシンボル(symbol)に変換する
Ruby2.1で確認
2つのHashを比較する際に、片方のHashはキーがシンボル、もう片方のHashはキーが文字列になっていたので、シンボルに統一するように変換することにしました。
その際にちょっとハマったのでメモ。
キーをシンボルに変換するにはactive_supportのsymbolize_keysメソッドが使えます。
ですが、深い階層のHashだと2階層目以降が変換されません。
2階層目以降も変換する用にはdeep_symbolize_keysメソッドが用意されています。
逆のパターンとしてシンボルを文字列に変換する場合はstringify_keys、deep_stringify_keysが用意されています。
以下サンプルです。
また、Hashの中にHashの配列が含まれていた場合はdeep_symbolize_keysメソッドを使っても変換できませんでした。
その場合はオーバーライドするか、別名のメソッドを作成する必要があるようです。
Qiitaの以下の記事を参考にさせていただきました。
Ruby 途中にArrayが入っても辿れるdeep_symbolize_keys
# diff.rb
require 'rubygems'
require 'hashdiff'
require 'active_support'
require 'active_support/core_ext'
sample = {
"aa" => {
"bb" => {
"cc" => [
111,
123,
],
},
},
}
# 文字列キーをシンボルに変換
p sample.symbolize_keys
# => {:aa=>{"bb"=>{"cc"=>["111", "123"]}}} # 第一階層しか変換されない
p sample.deep_symbolize_keys
# => {:aa=>{:bb=>{:cc=>["111", "123"]}}}
# シンボルキーを文字列に変換
p sample.deep_symbolize_keys.stringify_keys
# => {"aa"=>{:bb=>{:cc=>[111, 123]}}} # 第一階層しか変換されない
p sample.deep_symbolize_keys.deep_stringify_keys
# => {"aa"=>{"bb"=>{"cc"=>[111, 123]}}}
sample = {
"aa" => {
"bb" => {
"cc" => [
{
"dd" => 111,
},
{
"ee" => 123,
},
],
},
},
}
p sample.deep_symbolize_keys
# => {:aa=>{:bb=>{:cc=>[{"dd"=>111}, {"ee"=>123}]}}} # 配列が途中に入ると変換されない
class Hash
def deep_symbolize_keys
self.each_with_object({}) do |(key, val), memo|
if val.is_a?(Array)
val = val.map{|v| v.deep_symbolize_keys}
elsif val.is_a?(Hash)
val = val.deep_symbolize_keys
end
memo[key.to_s.to_sym] = val
end
end
end
p sample.deep_symbolize_keys
# => {:aa=>{:bb=>{:cc=>[{:dd=>111}, {:ee=>123}]}}} # 配列を含んでいても変換される