Techioz Blog

特定のキーの場合、すべての値をハッシュディープ変換します

概要

コミュニティに敬意を表します! 深くネストされたハッシュがあり、指定された特定のキーのすべての値を変換したいと考えています。 key == :something の場合の深い変換値のようなもの ハッシュの例:

{:id=>"11ed35b8e53c442ea210c39d6f24bddf",
 :createdAt=>"2022-09-16T12:12:55.454Z",
 :updatedAt=>"2022-09-16T12:12:55.454Z",
 :status=>"ACTIVE",
 :description=>"test",
 :goals=>
  [{:Definitions=>[],
    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
    :status=>"ACTIVE",
    :Definitions=>[{:text=>"Search for relics", :status=>"INACTIVE", :id=>"11ec1fc4bd36f876963867013cee2799"}],
    :id=>"11e818be2f0157329c76634ee23c1d8f"}],
 :healthConcernDefinitions=>[]}

すべてのキーのすべての値を変換したい:status 結果は次のようになります。

{:id=>"11ed35b8e53c442ea210c39d6f24bddf",
 :createdAt=>"2022-09-16T12:12:55.454Z",
 :updatedAt=>"2022-09-16T12:12:55.454Z",
 :status=>"TRANSFORMED",
 :description=>"test",
 :goals=>
  [{:Definitions=>[],
    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
    :status=>"TRANSFORMED",
    :Definitions=>[{:text=>"Search for relics", :status=>"TRANSFORMED", :id=>"11ec1fc4bd36f876963867013cee2799"}],
    :id=>"11e818be2f0157329c76634ee23c1d8f"}],
 :healthConcernDefinitions=>[]}

いくつかの解決策があります 最初の1つ:

hash_to_json = hash.to_json.gsub(/"ACTIVE"|"INACTIVE"/, '"TRANSFORMED"')
JSON.parse(hash_to_json)

二つ目:

hash.deep_transform_values { |v| (v == 'ACTIVE' || v == 'INACTIVE') ? 'TRANSFORMED' : v }

どちらのソリューションも機能していますが、値を一致させるのは好きではありません。特定のキーのみを一致させ、ハッシュ全体を変更して、次のようにしたいと考えています。

hash.deep_transform_keys { |k, v| v = 'TRANSFORMED' if k == :status }

どうもありがとう!!!

解決策

残念ながら、Hash#deep_transform_values はキーではなくブロックの値のみを受け取ります。そして残念なことに、Hash#deep_merge と Hash#deep_merge!それほど強力ではありません

独自のメソッドを作成できます。それは単なるアイデアです、あなたはそれを改善することができます

class Hash
  def deep_replace(hash)
    deep_dup.deep_replace!(hash)
  end

  def deep_replace!(hash)
    each_key do |key|
      hash.each do |k, v|
        self[key] = v if key == k
      end

      _replace_object!(self[key], hash)
    end
  end

  private

  def _replace_object!(object, hash)
    case object
    when Hash
      object.deep_replace!(hash)
    when Array
      object.map! { |v| _replace_object!(v, hash) }
    else
      object
    end
  end
end
hash = {:id=>"11ed35b8e53c442ea210c39d6f24bddf",
 :createdAt=>"2022-09-16T12:12:55.454Z",
 :updatedAt=>"2022-09-16T12:12:55.454Z",
 :status=>"ACTIVE",
 :description=>"test",
 :goals=>
  [{:Definitions=>[{:text=>"Search for relics", :status=>"INACTIVE", :id=>"11ec1fc4bd36f876963867013cee2799"}],
    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
    :status=>"ACTIVE",
    :id=>"11e818be2f0157329c76634ee23c1d8f"}],
  :healthConcernDefinitions=>[]}

その後、それを適用できます

# Replace one key
hash.deep_replace(status: "TRANSFORMED")

# => {:id=>"11ed35b8e53c442ea210c39d6f24bddf",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"TRANSFORMED",
# :description=>"test",
# :goals=>
#  [{:Definitions=>[{:text=>"Search for relics", :status=>"TRANSFORMED", :id=>"11ec1fc4bd36f876963867013cee2799"}],
#    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
#    :status=>"TRANSFORMED",
#    :id=>"11e818be2f0157329c76634ee23c1d8f"}],
#  :healthConcernDefinitions=>[]}
# Replace few keys
hash.deep_replace(status: "TRANSFORMED", txid: "555", id: "99999999999999999999999999999999")

# => {:id=>"99999999999999999999999999999999",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"TRANSFORMED",
# :description=>"test",
# :goals=>
#  [{:Definitions=>[{:text=>"Search for relics", :status=>"TRANSFORMED", :id=>"99999999999999999999999999999999"}],
#    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
#    :status=>"TRANSFORMED",
#    :id=>"99999999999999999999999999999999"}],
#  :healthConcernDefinitions=>[]}
# Check original (it wasn't changed)
hash

# => {:id=>"11ed35b8e53c442ea210c39d6f24bddf",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"ACTIVE",
# :description=>"test",
# :goals=>
#  [{:Definitions=>[{:text=>"Search for relics", :status=>"INACTIVE", :id=>"11ec1fc4bd36f876963867013cee2799"}],
#    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
#    :status=>"ACTIVE",
#    :id=>"11e818be2f0157329c76634ee23c1d8f"}],
#  :healthConcernDefinitions=>[]}
# Destructive method
hash.deep_replace!(status: "TRANSFORMED", id: "99999999999999999999999999999999")

# => {:id=>"99999999999999999999999999999999",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"TRANSFORMED",
# :description=>"test",
# :goals=>
#  [{:Definitions=>[{:text=>"Search for relics", :status=>"TRANSFORMED", :id=>"99999999999999999999999999999999"}],
#    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
#    :status=>"TRANSFORMED",
#    :id=>"99999999999999999999999999999999"}],
#  :healthConcernDefinitions=>[]}
# Check original (it was changed)
hash

# => {:id=>"99999999999999999999999999999999",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"TRANSFORMED",
# :description=>"test",
# :goals=>
#  [{:Definitions=>[{:text=>"Search for relics", :status=>"TRANSFORMED", :id=>"99999999999999999999999999999999"}],
#    :text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
#    :status=>"TRANSFORMED",
#    :id=>"99999999999999999999999999999999"}],
#  :healthConcernDefinitions=>[]}