Ruby-当年的group_by月份,包括没有数据的月份

时间:2019-05-08 02:06:37

标签: ruby-on-rails ruby ruby-on-rails-5

我正在尝试编写一种方法来为正在填充的图表返回非常具体的数据结构。

用户可以输入他们已经远足的里程的日期,因此在Mile模型中,我具有start_date和end_date属性。

我当前使用的方法是 close ,但是它应该在当月返回0,因为用户没有输入5月份的任何加息里程。我还需要将其限制为当前年份,而现在不是。

这是我当前的方法:

def miles_by_month
    miles = self.miles.from_this_year.group_by { |t| t.start_date.strftime('%b') }
    total_miles = miles.map do |m|
        { 'indicator': m[0], 'total': m[1].sum(&:length) }
    end
    total_miles
end

如果有帮助,还可以使用Mile模型的'from_this_year'范围:

scope :from_this_year, lambda { where("start_date > ? AND start_date < ?", Time.now.beginning_of_year, Time.now.end_of_year) }

这是返回值的示例:

[
    [0] {
        :indicator => "Jan",
            :total => 15
    },
    [1] {
        :indicator => "Feb",
            :total => 10
    },
    [2] {
        :indicator => "Mar",
            :total => 10
    },
    [3] {
        :indicator => "Apr",
            :total => 100
    },
    [4] {
        :indicator => "May",    # I need [4] to show up with 
        :total => 0             # a total of 0. [4] currently
    }                           # does not show up at all.
]

“指标”指的是月份的名称,“总计”指的是用户在该特定月份内远足的里程数的总和。

有什么建议吗?

更新1

我已经根据以下答案对我的miles_by_month方法进行了修改:

def miles_by_month
    months = Date::ABBR_MONTHNAMES[1..12]
    miles = self.miles.from_this_year.group_by { |t| t.start_date.strftime('%b') }

    total_miles = miles.map do |m|
        { 'indicator': m[0], 'total': m[1].sum(&:length) }
    end

    months.each do |month|
      unless total_miles.any? { |r| r[:indicator] == month }
        total_miles.push(indicator: month, total: 0)
      end
    end

    total_miles
  end

我剩下要做的唯一一件事就是弄清楚如何限制从年初到当前月份的月份变量。

2 个答案:

答案 0 :(得分:2)

您可以通过在每个月中循环并设置默认值来做到这一点,例如:

MONTHS = Date::ABBR_MONTHNAMES[1..12]

# put this somewhere
MONTHS.each do |month|
  unless results.any? { |r| r[:indicator] == month }
    results.push(indicator: month, total: 0)
  end
end

# you can sort them chronologically if needed
results.sort_by! { |r| MONTHS.index(r[:indicator]) }

请注意,这不是最有效的代码-它具有一些O(N ^ 2)东西,可以优化为O(N)-但希望它可以为您提供一个起点

答案 1 :(得分:0)

基于Max Pleaner的回答,我能够提出以下方法来正确返回所需的内容:

def miles_by_month
    cur_month = Time.now.month
    months = Date::ABBR_MONTHNAMES[1..cur_month]
    miles = self.miles.from_this_year.group_by { |t| t.start_date.strftime('%b') }

    total_miles = miles.map do |m|
        { 'indicator': m[0], 'total': m[1].sum(&:length) }
    end

    months.each do |month|
      unless total_miles.any? { |r| r[:indicator] == month }
        total_miles.push(indicator: month, total: 0)
      end
    end

    total_miles
  end

这将返回如下数据结构:

[
    [0] {
        :indicator => "Jan",
            :total => 15
    },
    [1] {
        :indicator => "Feb",
            :total => 10
    },
    [2] {
        :indicator => "Mar",
            :total => 10
    },
    [3] {
        :indicator => "Apr",
            :total => 100
    },
    [4] {
        :indicator => "May",
            :total => 0
    }
]

这当然不是最有效的方法,我很想知道是否有人有更有效的方法来处理此问题。