[英]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
,每个对应于一个元件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}
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.