Как добавить значения в массив, когда есть нулевая запись? - PullRequest
0 голосов
/ 27 декабря 2010

Я хочу создать реальный массив временных рядов.В настоящее время я использую гем статистики для извлечения значений для каждого «дня»:

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" для дней, которые отсутствовали в первом массиве, отсутствуют.

Ответы [ 2 ]

5 голосов
/ 27 декабря 2010
#!/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
0 голосов
/ 27 декабря 2010

Это работает:

#!/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]]

Большая часть кода готовит вещи либо для создания нового массива, либо для возврата объектов даты обратно в строки.

...