Home > Back-end >  How can I deep transform key or value in a hash/array only for the first occurence
How can I deep transform key or value in a hash/array only for the first occurence

Time:04-22

I have the following example

 input = {
    "books2" => [1, {a: 1, b: "seller35" }],
    "books3" => { "a" =>[{"5.5"=>"seller35", "6.5" => "foo"}]}
    }

And I would like to deep transform values in this has that matches seller35. However, only for the first occurrence. So for b: "seller35". "5.5"=>"seller35" should stay intact.

Ideally, for key, value and/or element in array.

I looked at: https://apidock.com/rails/v6.0.0/Hash/_deep_transform_keys_in_object for inspiration but couldn't figure out a solution. That does it for all

input.deep_transform_values { |value| value == "seller35" ? "" : value }
=> {"books2"=>[1, {:a=>1, :b=>""}], "books3"=>{"a"=>[{"5.5"=>"", "6.5"=>"foo"}]}}

Thanks!

CodePudding user response:

You can create a done boolean value to keep track of whether a replacement has been done or not yet and return an appropriate value from the block:

require "active_support/core_ext/hash/deep_transform_values"

def deep_transform_values_once(hash:, old_value:, new_value:)
  done = false
  hash.deep_transform_values do |value|
    if !done && value == old_value
      done = true
      new_value
    else
      value
    end
  end
end

input = {
  "books2" => [1, { a: 1, b: "seller35" }],
  "books3" => { "a" => [{ "5.5" => "seller35", "6.5" => "foo" }] },
}

p deep_transform_values_once(hash: input, old_value: "seller35", new_value: "")

Output:

{"books2"=>[1, {:a=>1, :b=>""}], "books3"=>{"a"=>[{"5.5"=>"seller35", "6.5"=>"foo"}]}}
  • Related