简体   繁体   English

如何映射哈希数组并在空日期项目上输出0?

[英]How do I map an array of hashes and output 0 on empty date items?

I have an array of hashes: 我有一系列哈希:

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}
]

You'll notice, there are a number of dates missing in the sequence (3, 7 and 8). 您会注意到,序列(3、7和8)中缺少许多日期。

I have a map that outputs those hashes into an array of only the amounts for the hashes that match a range of dates: 我有一张map ,将这些散列输出到仅包含与日期范围匹配的散列数量的数组中:

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

Right now, that outputs the full contents of the amount items into an array: [16611, 16611, 9428, 11628, 4600, 21756, 18127] 现在,它将amount项目的全部内容输出到一个数组中: [16611, 16611, 9428, 11628, 4600, 21756, 18127]

But what I need it to do is insert a 0 for the dates that are missing from the range. 但是我需要做的是为范围中缺少的日期插入一个0 So in my example, my range goes from December 1 - December 12. So the output would be: 因此,在我的示例中,我的范围是12月1日至12月12日。因此,输出为:

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

How can I do that? 我怎样才能做到这一点?

Because everyone likes a one-liner: 因为每个人都喜欢单线:

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]}

Basically, create an array of the dates we want with empty values, add the real values to the end of the array. 基本上,使用空值创建我们想要的日期的数组,然后将实值添加到数组的末尾。 Convert to a hash, thereby overriding the earlier empty values where they exist, and then iterate over the result. 转换为哈希,从而覆盖它们存在的较早的空值,然后遍历结果。 In Ruby >=1.9.2 you get the keys out in their original sequence. 在Ruby> = 1.9.2中,您可以按原始顺序获得密钥。

[16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 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] [16611、16611、0、9428、11628、4600、0、0、21756、18127、0、0]

Given a date range: 给定日期范围:

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

and assuming the dates in items are unique, which appears to be the case, I would do it this way: 并假设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]

We first create a hash with elements k=>v , each corresponding to an element h of items such that k = Date.parse(h[:created]) and v = h[:amount] : 我们首先创建的元素的哈希k=>v ,每个对应于一个元件hitems ,使得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}

Next we use map to convert each member d of the range r into b[d] if b contains a key d , else d is converted to zero. 接下来,如果b包含键d ,则使用map将范围r每个成员d转换为b[d] ,否则d转换为零。

Alternatively, we could do it like this: 另外,我们可以这样做:

items.each_with_object({}) { 
  |g,h| h[Date.parse(g[:created])] = g[:amount] }
    .values_at(*(rng.to_a))
    .map {|v| v.nil? ? 0 : v}

After calculating the hash as above, we use Hash#values_at to create an array that contains the values in the hash, plus nil for each date in rng for which there is no match in b : 在按上述方式计算完哈希之后,我们使用Hash#values_at创建一个数组,其中包含哈希中的值,以及rng每个日期的nil ,而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]

Lastly, map the nil s to zero: 最后,将nil映射为零:

c.map {|v| v.nil? ? 0 : v}
  #=> [16611, 16611, 0, 9428, 11628, 4600, 0, 0, 21756, 18127, 0, 0]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM