-1

I would like to transform this

def some_process(k,v)
    return "#{v}_#{k}"
end

a_hash = {
    "i_love_hashes" => {
        "thing" => 20,
        "other_thing" => "0",
        "yet_another_thing" => "i disagree",
        "_peculiar_thing" => [
            {"count" => 30,
            "name" => "freddie"},
            {"count" => 15,
            "name" => "johhno"},
            {"count" => 12,
            "name" => "mohammed"},
        ]
    },
    "as_do_i" => {
       "thing" => 10,
       "other_thing" => "2",
       "yet_another_thing" => "i strongly agree",
       "_peculiar_thing" => [
           {"count" => 10,
           "name" => "frodo"},
           {"count" => 4,
           "name" => "bilbo"},
           {"count" => 2,
           "name" => "elizabeth"},
       ] 
    }
}

into this

{
"i_love_hashes"=>{
    "thing"=>20, 
    "other_thing"=>"0", 
    "yet_another_thing"=>"i disagree", 
    "_peculiar_thing"=> [
        {"count"=>30, "name"=>"freddie", :sinister_name=>"freddie_i_love_hashes"}, 
        {"count"=>15, "name"=>"johhno", :sinister_name=>"johhno_i_love_hashes"}, 
        {"count"=>12, "name"=>"mohammed", :sinister_name=>"mohammed_i_love_hashes"}
        ]}, 
"as_do_i"=>{
    "thing"=>10, 
    "other_thing"=>"2", 
    "yet_another_thing"=>"i strongly agree", 
    "_peculiar_thing"=>[
        {"count"=>10, "name"=>"frodo", :sinister_name=>"frodo_as_do_i"},
        {"count"=>4, "name"=>"bilbo", :sinister_name=>"bilbo_as_do_i"}, 
        {"count"=>2, "name"=>"elizabeth", :sinister_name=>"elizabeth_as_do_i"}
        ]
    }
}

this is the code I am currently using to achieve this

a_hash.each_with_object({}) do |(k,v),o|
  o.merge!({k =>
      v.each_with_object({}) do |(a,b),g|
        g.merge!({ a =>
          (b.is_a?(Array) ? b.collect {|x| x.merge({sinister_name: (some_process k, x["name"])})} : b)
          })
      end
    })
end

Ignoring the specific details of what is being returned by "some_process" (what is important is that it depends on the outer most key and the inner name values, in this example), are there any alternatives that would be considered more elegant?

OhNoez Woez
  • 105
  • 5
  • Why `.each_with_object()` and not `inject()`? – Phlip Nov 21 '13 at 22:58
  • 1
    @Phlip I would almost always use inject for this but the second answer [here](http://stackoverflow.com/questions/5481009/why-is-enumerableeach-with-object-deprecated) gives a credible reason why each_with_object is valid. – Mike H-R Nov 22 '13 at 00:25
  • @Phlip: what would the equivalent inject-based version be? – OhNoez Woez Nov 24 '13 at 22:43
  • It turns out, http://stackoverflow.com/questions/5481009/why-is-enumerableeach-with-object-deprecated , that `each_with_object` is merely `inject` without the need to return the hash (in your case) at the end of each block. – Phlip Nov 25 '13 at 01:00
  • given I can write your algorithm as `a_hash.each do |key, value| value['_peculiar_thing'].map do |h| h.merge! :sinister_name => "#{ h['name'] }_i_love_hashes" end end`, if I don't mind stomping on your input `a_hash`, you could also dispense with `each_with_object` altogether and merely deep-clone `a_hash` before you start. if you mind it gets stomped on. – Phlip Nov 25 '13 at 01:02

1 Answers1

0

Why not do a recursive function?

def add_siniter(hash) 
  hash[:siniter_name] = "#{hash['name']}_i_love_hashes"
  hash
end

def format_hash(item)
  case item
    when Hash  then item.keys.each{|key| format_hash(item[key])}
    when Array then item.map!{|h| add_siniter(h)}
  end
end

format_hash(a_hash)
hirolau
  • 13,451
  • 8
  • 35
  • 47
  • While I like the idea of a recursive method, the top level keys would need to be passed down, along with a depth parameter, to make it work, in this case. – OhNoez Woez Nov 24 '13 at 22:30
  • Also, the format_hash method you've provided only appears to return an array of the two top-level keys, when run with the provided hash. – OhNoez Woez Nov 24 '13 at 22:31