LoginSignup
35
32

More than 5 years have passed since last update.

YAML や JSON のような構造のオブジェクトに対して再帰的に処理を加えるイディオム

Posted at

YAML や JSON で表現されるような、スカラー値、Array、Hash で構成されたオブジェクトについて、再帰的に処理をする際、下記のようなイディオムが使える。

def foo(obj)
  case obj
  when Array
    obj.map{|e| foo(e)} # Array の要素を再帰的に処理
  when Hash
    obj.inject({}) do |hash, (k, v)|
      hash[k] = foo(v) # Hash の値を再帰的に処理
      hash
    end
  else
    obj
  end
end

例. Hash のキーを to_s する

def stringify_keys(obj)
  case obj
  when Array
    obj.map{|e| stringify_keys(e)}
  when Hash
    obj.inject({}) do |hash, (k, v)|
      # ここが変わる
      hash[k.to_s] = stringify_keys(v)
      hash
    end
  else
    obj
  end
end
stringify_keys({a: 1, b: [{c: 3}]}) #=> {"a"=>1, "b"=>[{"c"=>3}]}

例. スカラー値を to_s する

def stringify_values(obj)
  case obj
  when Array
    obj.map{|e| stringify_values(e)}
  when Hash
    obj.inject({}) do |hash, (k, v)|
      hash[k] = stringify_values(v)
      hash
    end
  else
    # ここが変わる
    obj.to_s
  end
end
stringify_values({a: 1, b: [{c: 3}]}) #=> {:a=>"1", :b=>[{:c=>"3"}]}

例. Array を、インデックスをキーとする Hash に置き換える

def hash_arrays(obj)
  case obj
  when Array
    # ここが変わる
    Hash[
      obj.each_with_index.map do |e, i|
        [i, hash_arrays(e)]
      end
    ]
  when Hash
    obj.inject({}) do |hash, (k, v)|
      hash[k] = hash_arrays(v)
      hash
    end
  else
    obj
  end
end
hash_arrays({a: 1, b: [{c: 3}]}) #=> {:a=>1, :b=>{0=>{:c=>3}}}
35
32
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
32