我不同意这足以保证使用 SQL 或 Arel。你需要的结果的 95% 就在那里,剩下的应该是微不足道的。
方法一
如果您只想从哈希中获取值,请考虑在哈希上定义一个默认值,如下所示:
points_by_week =
Hash.
new(0).
merge(
Log.
where(user_id: user_id).
group("DATE_TRUNC('year', created_at)", "DATE_TRUNC('week', created_at)").
sum(:points)
)
然后,无论何时调用:
points_by_week[x]
...如果 x 不在散列中,则返回 0。
如果不存在的键需要 nil,那么您将传递 nil 而不是 0 到 Hash.new
方法二
或者,如果您确实需要在散列中填充整个值集,您可以根据范围(我使用过此处为 0 到 100 的整数):
Hash[*(0..5).to_a.zip(Array.new(6,0)).flatten]
=> {0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0}
...或...
Hash[*(0..5).to_a.zip(Array.new(6)).flatten]
=> {0=>nil, 1=>nil, 2=>nil, 3=>nil, 4=>nil, 5=>nil}
(也许有更方便的方法),然后#reverse_merge 使用您当前的哈希值。
例如
2.2.5 :036 > x = {1 => 1, 3 => 3}
=> {1=>1, 3=>3}
2.2.5 :037 > y = Hash[*(0..5).to_a.zip(Array.new(6,0)).flatten]
=> {0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0}
2.2.5 :038 > z = x.reverse_merge(y)
=> {0=>0, 1=>1, 2=>0, 3=>3, 4=>0, 5=>0}
星期一日期的数组可以通过以下方式生成:
mondays = (Date.parse("2017-04-17")..(Date.parse("2017-04-17")+20.weeks)).map(&:to_time).select(&:monday?)
... 并转换为 [year,date] 对 ...
year_monday_pairs = mondays.map{|d| [d.beginning_of_year, d] }
... 并转换为 #reverse_merge 所需的哈希 ...
Hash[*year_monday_pairs.zip(Array.new(year_monday_pairs.size, 0)).flatten(1)]
=> {[2017-01-01 00:00:00 +0000, 2017-04-17 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-04-24 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-05-01 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-05-08 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-05-15 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-05-22 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-05-29 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-06-05 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-06-12 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-06-19 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-06-26 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-07-03 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-07-10 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-07-17 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-07-24 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-07-31 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-08-07 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-08-14 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-08-21 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-08-28 00:00:00 +0100]=>0, [2017-01-01 00:00:00 +0000, 2017-09-04 00:00:00 +0100]=>0}