Techioz Blog

Rubyはフラット化されたハッシュをネストされたハッシュに変換します

概要

私は次のものを持っています:

{ :a_b_c => 42, :a_b_d => 67, :a_d => 89, :e => 90 }

これを以下のように変換するにはどうすればよいですか

{ a: { b: { c: 42, d: 67 }, d: 89 }, e: 90 } 

解決策

ActiveSupport を備えた Rail には Hash#deep_merge と Hash#deep_merge があります。

持っていない場合は、定義できます

class Hash
  def deep_merge(other_hash, &block)
    dup.deep_merge!(other_hash, &block)
  end

  def deep_merge!(other_hash, &block)
    merge!(other_hash) do |key, this_val, other_val|
      if this_val.is_a?(Hash) && other_val.is_a?(Hash)
        this_val.deep_merge(other_val, &block)
      elsif block_given?
        block.call(key, this_val, other_val)
      else
        other_val
      end
    end
  end
end

または、これらのメソッドを必要とするだけです

require 'active_support/core_ext/hash/deep_merge'

そして最後に

hash =
  { :a_b_c => 42, :a_b_d => 67, :a_d => 89, :e => 90 }

hash.each_with_object({}) do |(k, v), h|
  h.deep_merge!(k.to_s.split('_').map(&:to_sym).reverse.reduce(v) { |assigned_value, key| { key => assigned_value } })
end

# => {:a=>{:b=>{:c=>42, :d=>67}, :d=>89}, :e=>90}