如何映射散列数组并在空日期项上输出0?

时间:2014-02-11 00:40:47

标签: ruby arrays hash

我有一系列哈希:

items = [
   {:created=>"2013-12-01", :amount=>16611},
   {:created=>"2013-12-02", :amount=>16611}, 
   {:created=>"2013-12-04", :amount=>9428},
   {:created=>"2013-12-05", :amount=>11628},
   {:created=>"2013-12-06", :amount=>4600},
   {:created=>"2013-12-09", :amount=>21756},
   {:created=>"2013-12-10", :amount=>18127}
]

您会注意到,序列中缺少许多日期(3,7和8)。

我有map将这些哈希值输出到只包含与日期范围匹配的哈希值的数组中:

items.select{ |key| (Date.parse("December 1, 2013")..Date.parse("December 12, 2013")).include? Date.parse(key[:created])}.map { |key| key[:amount] }

现在,它将amount项的全部内容输出到一个数组中:[16611, 16611, 9428, 11628, 4600, 21756, 18127]

但我需要它做的是为范围中缺少的日期插入0。所以在我的例子中,我的范围从12月1日到12月12日。所以输出将是:

[16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 0]

我该怎么做?

3 个答案:

答案 0 :(得分:1)

因为每个人都喜欢单行:

Hash[(Date.parse("December 1, 2013")..Date.parse("December 12, 2013")).map { |x| [x,{:created=>x,:amount=>0}]}+ items.map { |x| [Date.parse(x[:created]),x] }].map { |i| i[1][:amount]}

基本上,使用空值创建我们想要的日期数组,将实际值添加到数组的末尾。转换为哈希值,从而覆盖它们存在的早期空值,然后迭代结果。在Ruby> = 1.9.2中,您可以按原始顺序获取密钥。

[16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 0]

答案 1 :(得分:0)

lookup = Hash[*items.flat_map { |it| [Date.parse(it[:created]),it[:amount]] }]

(0..11).map { |i| lookup.fetch(Date.new(2013,12,1)+i,0) }
  

[16611,16611,0,9428,11628,4600,0,0,21756,18127,0,0]

答案 2 :(得分:0)

给定日期范围:

r = (Date.parse("December 1, 2013")..Date.parse("December 12, 2013"))

并假设items中的日期是唯一的,看起来就是这种情况,我会这样做:

b = items.each_with_object({}) {|g,h| h[Date.parse(g[:created])] = g[:amount]}
r.map { |d| b[d] ? b[d] : 0 }
   #=> [16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 0]

我们首先使用元素k=>v创建一个哈希,每个哈希都对应h items的元素k = Date.parse(h[:created]),以便v = h[:amount]b = items.each_with_object({}) {|g,h| h[Date.parse(g[:created])] = g[:amount]} #=> {#<Date: 2013-12-01 ((2456628j,0s,0n),+0s,2299161j)>=>16611, # #<Date: 2013-12-02 ((2456629j,0s,0n),+0s,2299161j)>=>16611, # #<Date: 2013-12-04 ((2456631j,0s,0n),+0s,2299161j)>=> 9428, # #<Date: 2013-12-05 ((2456632j,0s,0n),+0s,2299161j)>=>11628, # #<Date: 2013-12-06 ((2456633j,0s,0n),+0s,2299161j)>=> 4600, # #<Date: 2013-12-09 ((2456636j,0s,0n),+0s,2299161j)>=>21756, # #<Date: 2013-12-10 ((2456637j,0s,0n),+0s,2299161j)>=>18127}

map

如果d包含密钥r,我们会使用b[d]b范围内的每个成员d转换为d,否则items.each_with_object({}) { |g,h| h[Date.parse(g[:created])] = g[:amount] } .values_at(*(rng.to_a)) .map {|v| v.nil? ? 0 : v} 转换为零。

或者,我们可以这样做:

nil

如上所述计算哈希后,我们使用Hash#values_at创建一个包含哈希值的数组,并为rng中的每个日期添加b,但没有匹配在c = items.each_with_object({}) {|g,h| h[Date.parse(g[:created])] = g[:amount]}.values_at(*rng.to_a) #=> [16611, 16611, nil, 9428, 11628, 4600, nil, nil, 21756, 18127, nil, nil]

nil

最后,将c.map {|v| v.nil? ? 0 : v} #=> [16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 0] s映射到零:

{{1}}