【问题标题】:How do I add values in an array when there is a null entry?有空条目时如何在数组中添加值?
【发布时间】:2011-05-31 00:55:22
【问题描述】:

我想创建一个实时序列数组。目前,我正在使用统计 gem 提取每个“天”的值:

define_statistic :sent_count, :count
=> :all, :group => 'DATE(date_sent)',    
:filter_on => {:email_id => 'email_id
> = ?'}, :order => 'DATE(date_sent) ASC'

这样做是创建一个数组,其中包含日期值,例如

[["12-20-2010",1], ["12-24-2010",3]]

但我需要它来填充空值,所以看起来更像:

[["12-20-2010",1], ["12-21-2010",0], ["12-22-2010",0], ["12-23-2010",0], ["12-24-2010",3]]

请注意第二个示例如何将第一个数组中缺少的天数设为“0”。

【问题讨论】:

  • 这听起来像是一个统计宝石的问题;你能链接到更多的细节吗?
  • 我认为这可以用一些 ruby​​ 数组函数来填充空值,但这里是链接:github.com/acatighera/statistics

标签: ruby-on-rails ruby arrays statistics time-series


【解决方案1】:

这行得通:

#!/usr/bin/env ruby

require 'pp'
require 'date'

# convert the MM-DD-YYYY format date string to a Date
DATE_FORMAT = '%m-%d-%Y'
def parse_date(s)
  Date.strptime(s, DATE_FORMAT)
end

dates = [["12-20-2010",1], ["12-24-2010",3]]

# build a hash of the known dates so we can skip the ones that already exist.
date_hash = Hash[*dates.map{ |i| [parse_date(i[0]), i[-1]] }.flatten]

start_date_range = parse_date(dates[0].first) 
end_date_range   = parse_date(dates[-1].first)

# loop over the date range...
start_date_range.upto(end_date_range) do |d|
  # ...and adding entries for the missing ones.
  date_hash[d] = 0 if (!date_hash.has_key?(d))
end

# convert the hash back into an array with all dates
all_dates = date_hash.keys.sort.map{ |d| [d.strftime(DATE_FORMAT), date_hash[d] ] }
pp all_dates

# >> [["12-20-2010", 1],
# >>  ["12-21-2010", 0],
# >>  ["12-22-2010", 0],
# >>  ["12-23-2010", 0],
# >>  ["12-24-2010", 3]]

大部分代码都在准备东西,要么构建一个新数组,要么将日期对象返回为字符串。

【讨论】:

  • 酷,你建议我如何创建它?它是否可能是一个库,以便我可以获取原始数组并在其上运行一个方法?比如 dates.convert_to_timeseries ?
【解决方案2】:
#!/usr/bin/ruby1.8

require 'date'
require 'pp'

def add_missing_dates(series)
  series.map do |date, value|
    [Date.strptime(date, '%m-%d-%Y'), value]
  end.inject([]) do |series, date_and_value|
    filler = if series.empty?
               []
             else
               ((series.last[0]+ 1)..(date_and_value[0] - 1)).map do |date|
                 [date, 0]
               end
             end
    series + filler + [date_and_value]
  end.map do |date, value|
    [date.to_s, value]
  end
end

a = [["12-20-2010",1], ["12-24-2010",3]]
pp add_missing_dates(a)
# => [["2010-12-20", 1],
# =>  ["2010-12-21", 0],
# =>  ["2010-12-22", 0],
# =>  ["2010-12-23", 0],
# =>  ["2010-12-24", 3]]

我建议不要对基类进行猴子修补以包含此方法:这不是通用的;即使它是,它也不需要在那里。我会把它放在一个模块中,你可以将它混合到任何需要它的代码中:

module AddMissingDates
  def add_missing_dates(series)
    ...
  end
end

class MyClass
  include AddMissingDates
  ...
end

但是,如果你真的想要:

def Array.add_missing_dates(series)
  ...
end

【讨论】:

  • 对,是的,我想把它作为一个模块来做,所以我将它作为 add_missing_dates.rb 存储在 lib/ 目录中?
  • 我明白了...谢谢...我在“pp”上进行了谷歌搜索,以便更好地了解正在做什么,但我找不到它。什么是'pp'? :)
  • @Angela,这就像 p,将对象检查到标准输出的标准方法,但输出更漂亮(我认为 pp 代表“漂亮打印”)。 ruby-doc.org/core/files/lib/pp_rb.html
  • @wayne,谢谢,很抱歉你的优雅解决方案这么慢,我在系列 + 填充 + [date_and_value] 上迷路了。似乎系列应该代表转换为日期的原始值,并且您使用注入进入中间并添加日期填充符0。但是什么是 date_and_value 呢?谢谢...对不起,在我实施时试图理解....:\
  • @wayne -- 嗨,我收到一个无效的日期错误,由于我没有获得更多信息,所以不知道如何调试它,它在 strptime 行附近
猜你喜欢
  • 2015-01-13
  • 2015-10-15
  • 2013-12-07
  • 1970-01-01
  • 1970-01-01
  • 2017-04-11
  • 2022-08-18
  • 1970-01-01
  • 2016-02-09
相关资源
最近更新 更多