获取现有哈希的密钥并为其提供默认值

时间:2016-10-05 11:54:14

标签: ruby hash fetch

给定现有哈希,例如:

{
  "April_data" : {
    "April" : 10,
    "May" : 8,
    "June" : 7,
    "July" : 7,
    "August" : 5,
    "September" : 2
  },
  "May_data" : {
    "May" : 4,
    "June" : 3,
    "July" : 2,
    "August" : 2,
    "September" : 0
  },
  "June_data" : {
    "June" : 12,
    "July" : 12,
    "August" : 8,
    "September" : 2
  }
}

如何在其他月份保留“April_data”中包含的所有密钥并指定默认值(例如“0”)?结果如下:

{
  "April_data" : {
    "April" : 10,
    "May" : 8,
    "June" : 7,
    "July" : 7,
    "August" : 5,
    "September" : 2
  },
  "May_data" : {
    "April": 0,
    "May" : 4,
    "June" : 3,
    "July" : 2,
    "August" : 2,
    "September" : 0
  },
  "June_data" : {
    "April": 0,
    "May": 0,
    "June" : 12,
    "July" : 12,
    "August" : 8,
    "September" : 2
  }
}

任何帮助apreciated

2 个答案:

答案 0 :(得分:2)

stub = hash.each_with_object({}) do |(_, v), memo|
  memo.merge!(v)
end.map { |k, v| [k, 0] } # or end.keys.product([0]).to_h
   .to_h
#⇒ {"April"=>0, "May"=>0, "June"=>0, "July"=>0, "August"=>0, "September"=>0}

hash.map { |k, v| [k, stub.merge(v)] }.to_h
#⇒ desired result

答案 1 :(得分:1)

诀窍是要记住哈希会覆盖现有的键,所以从默认值开始,用你想要保留的键覆盖它们:

DEFAULTS = {
  "April" => 0,
  "May" => 0,
  "June" => 0,
  "July" => 0,
  "August" => 0,
  "September" => 0
}

data = {
  "April_data" => {
    "April" => 10,
    "May" => 8,
    "June" => 7,
    "July" => 7,
    "August" => 5,
    "September" => 2
  },
  "May_data" => {
    "May" => 4,
    "June" => 3,
    "July" => 2,
    "August" => 2,
    "September" => 0
  },
  "June_data" => {
    "June" => 12,
    "July" => 12,
    "August" => 8,
    "September" => 2
  }
}

data.each do |k, v|
  data[k] = DEFAULTS.merge(v)
end

结果是:

require 'ap'
ap data

# >> {
# >>   "April_data" => {
# >>     "April"     => 10,
# >>     "May"       => 8,
# >>     "June"      => 7,
# >>     "July"      => 7,
# >>     "August"    => 5,
# >>     "September" => 2
# >>   },
# >>   "May_data"   => {
# >>     "April"     => 0,
# >>     "May"       => 4,
# >>     "June"      => 3,
# >>     "July"      => 2,
# >>     "August"    => 2,
# >>     "September" => 0
# >>   },
# >>   "June_data"  => {
# >>     "April"     => 0,
# >>     "May"       => 0,
# >>     "June"      => 12,
# >>     "July"      => 12,
# >>     "August"    => 8,
# >>     "September" => 2
# >>   }
# >> }

如果你不确定键应该是什么,或者,如果你像我一样懒惰并想让Ruby为你定义默认值,你可以扫描子哈希并让Ruby搞清楚:

DEFAULTS = data.flat_map{ |k, v| v.keys}.uniq.map{ |k| [k, 0] }.to_h
# => {"April"=>0, "May"=>0, "June"=>0, "July"=>0, "August"=>0, "September"=>0}

这是正在做的事情:

DEFAULTS = data
          .flat_map{ |k, v| v.keys} # => ["April", "May", "June", "July", "August", "September", "May", "June", "July", "August", "September", "June", "July", "August", "September"]
          .uniq # => ["April", "May", "June", "July", "August", "September"]
          .map{ |k| [k, 0] } # => [["April", 0], ["May", 0], ["June", 0], ["July", 0], ["August", 0], ["September", 0]]
          .to_h
# => {"April"=>0, "May"=>0, "June"=>0, "July"=>0, "August"=>0, "September"=>0}

或者,但不一定更快或更简洁:

DEFAULTS = data.values # => [{"April"=>10, "May"=>8, "June"=>7, "July"=>7, "August"=>5, "September"=>2}, {"May"=>4, "June"=>3, "July"=>2, "August"=>2, "September"=>0}, {"June"=>12, "July"=>12, "August"=>8, "September"=>2}]
               .flat_map(&:keys) # => ["April", "May", "June", "July", "August", "September", "May", "June", "July", "August", "September", "June", "July", "August", "September"]
               .uniq # => ["April", "May", "June", "July", "August", "September"]
               .map{ |k| [k, 0] }.to_h  # => {"April"=>0, "May"=>0, "June"=>0, "July"=>0, "August"=>0, "September"=>0}