My respect to community!
I have deep nested hash and I want to transform all values of specific key provided. Something like deep transform values if key == :something
Example of hash:
{: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=>[]}
I want to transform all values of all keys :status
Result must be:
{: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=>[]}
I have a couple solutions First one:
hash_to_json = hash.to_json.gsub(/"ACTIVE"|"INACTIVE"/, '"TRANSFORMED"')
JSON.parse(hash_to_json)
Second one:
hash.deep_transform_values { |v| (v == 'ACTIVE' || v == 'INACTIVE') ? 'TRANSFORMED' : v }
Both solutions are working but I do not like to match values, I want to match only specific key and change it all over the hash, somting like:
hash.deep_transform_keys { |k, v| v = 'TRANSFORMED' if k == :status }
Thanks a lot!!!
CodePudding user response:
We could implement a conditional overwrite of a key using an implementation akin to deep_transform_keys
.
def deep_overwrite(object, other_h)
case object
when Hash
object.each_with_object({}) do |(key, value), result|
result[key] = other_h[key] || deep_overwrite(value, other_h)
end
when Array
object.map { |e| deep_overwrite(e,other_h) }
else
object
end
end
While this does not take a block format (as shown in your post), that did not seems to be necessary based on your use case. Instead this will simply overwrite the value of any key (nested at any level) contained in the original (object
) that is also contained in other_h
.
To call this in your case
original = {:id=>"11ed35b8e53c442ea210c39d6f24bddf",
:createdAt=>"2022-09-16T12:12:55.454Z",
:updatedAt=>"2022-09-16T12:12:55.454Z",
:status=>"ACTIVE",
:description=>"test",
:goals=>
[{:text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
:status=>"ACTIVE",
:Definitions=>[{:text=>"Search for relics", :status=>"INACTIVE", :id=>"11ec1fc4bd36f876963867013cee2799"}],
:id=>"11e818be2f0157329c76634ee23c1d8f"}],
:healthConcernDefinitions=>[]}
result = deep_overwrite(original,{status: 'TRANSFORMED'})
#=> {:id=>"11ed35b8e53c442ea210c39d6f24bddf",
# :createdAt=>"2022-09-16T12:12:55.454Z",
# :updatedAt=>"2022-09-16T12:12:55.454Z",
# :status=>"TRANSFORMED",
# :description=>"test",
# :goals=>
# [{:text=>"Follows Action Plan Appropriately, Worse or Warning Symptoms",
# :status=>"TRANSFORMED",
# :Definitions=>
# [{:text=>"Search for relics",
# :status=>"TRANSFORMED",
# :id=>"11ec1fc4bd36f876963867013cee2799"}],
# :id=>"11e818be2f0157329c76634ee23c1d8f"}],
# :healthConcernDefinitions=>[]}
CodePudding user response:
Unfortunely Hash#deep_transform_values
takes in block only values, not keys. And unfortunely Hash#deep_merge
and Hash#deep_merge!
are not so powerful
You can write your own method(s). It is just idea, you can improve it
class Hash
def deep_replace(hash)
deep_dup.deep_replace!(hash)
end
def deep_replace!(hash)
each do |key, value|
hash.each do |k, v|
self[key] = v if key == k
end
case value
when Hash
value.deep_replace!(hash)
when Array
value.map! { |v| v.deep_replace!(hash) }
end
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=>[]}
And after that you can apply it
# 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=>"ACTIVE",
# :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=>"TRANSFORMED",
# :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=>"ACTIVE",
# :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=>"ACTIVE",
# :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=>[]}