Home > other >  Convert true-false strings to boolean & Skip the rest in a hash
Convert true-false strings to boolean & Skip the rest in a hash

Time:04-09

I have a hash that contains 2 arrays of hashes

h = {
  "budget_options"=>[
    {"amount"=>"1.0", "text"=>"budget options"},
    {"amount"=>"2.0", "most_popular"=>"true", "text"=>"budget options"},
    {"amount"=>"3.0", "text"=>"budget options"}
  ],
  "pcb_budget_options"=>[
    {"amount"=>"1.0"},
    {"amount"=>"0.0"},
    {"amount"=>"-1.0", "most_popular"=>"true"}
  ]
}

I just want to convert "most_popular" value from string to boolean I tried to do this but it ends up with n3 time complexity.

Is there a built-in method to do this? Any kind of help will be appriciated.

CodePudding user response:

I think this does what you want. I have not calculated the O of it. I used the Marshal#dump/load trick to do a deep copy of the object before manipulating it.

mp = "most_popular"
obj = Marshal.load(Marshal.dump(h))
obj.each_key {|k| obj[k].each {|v| v[mp] = v[mp] == "true" ? true : false if v[mp] }}

Also see Cary's comment below for a slightly more terse version of the inner block.

CodePudding user response:

If you do not wish to mutate h you can write

h.transform_values do |arr|
  arr.map do |g|
    g.merge({})
     .tap { |f| f["most_popular"] = f["most_popular"]=="true" if f.key?("most_popular") }
  end
end
  #=> {
  #     "budget_options"=>[
  #       {"amount"=>"1.0", "text"=>"budget options"},
  #       {"amount"=>"2.0", "most_popular"=>true, "text"=>"budget options"},
  #       {"amount"=>"3.0", "text"=>"budget options"}
  #     ],
  #     "pcb_budget_options"=>[
  #       {"amount"=>"1.0"},
  #       {"amount"=>"0.0"},
  #       {"amount"=>"-1.0", "most_popular"=>true}
  #     ]
  #   }

The purpose of g.merge({}) is to avoid mutating the inner hashes. See Hash#transform_values, Hash#merge and Object#tap.

  • Related