在 Ruby/Rails 中对日期系列进行分组的最佳方式是什么?



从一系列日期,

arr = ["2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08",
"2020-01-09", "2020-02-12", "2020-02-13", "2020-02-14"]     

我们如何对它们进行分组,例如输出变为如下:

["Jan 5th - Jan 9th", "Feb 12th - Feb 14th"]

属于该范围内的日期应按上述方式分组。众所周知,arr的所有元素的年份都相同,因此可以忽略不计。

我想说你可以用to_date转换它们,按它们的month分组,并按它们的minmax映射它们:

arr
.map(&:to_date)
.group_by(&:month)
.map do |_, dates|
dates.minmax.map { |date| date.to_s(:long_ordinal) }.join(' - ')
end
# ["January 5th, 2020 - January 9th, 2020", "February 12th, 2020 - February 14th, 2020"]

to_s(:long_ordinal)是获取格式化字符串。

arr = ["2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08", "2020-01-09", "2020-02-12", "2020-02-13", "2020-02-14"]
arr
.map { |d| Date.parse(d) }
.group_by { |d| d.month }
.sort
.map do |d| 
dt = d.last
min = dt.min
max = dt.max
"#{min.strftime('%b')} #{min.day.ordinalize} - #{max.strftime('%b')} #{dt.max.day.ordinalize}"
end

您可以按如下方式执行此操作。

require 'date'
ORDINAL = { 1=>"st", 2=>"nd", 3=>"rd" }.tap { |h| h.default = "th" } 
arr.group_by { |s| s[5,2] }.
map do |mon, arr|
mon_name = Date::ABBR_MONTHNAMES[mon.to_i]
first_day, last_day = arr.map { |s| s[-2,2].to_i }.minmax.
map { |d| "%d%s" % [d, ORDINAL[d%10]] }
"%s %s - % s %s" % [mon_name, first_day, mon_name, last_day]
end
#=> ["Jan 5th - Jan 9th", "Feb 12nd - Feb 14th"] 

步骤如下:

ORDINAL = { 1=>"st", 2=>"nd", 3=>"rd" }.tap { |h| h.default = "th" }

ORDINAL[0] #=> "th" 
ORDINAL[1] #=> "st" 
ORDINAL[2] #=> "nd" 
ORDINAL[3] #=> "rd" 
ORDINAL[4] #=> "th"
...

h = arr.group_by { |s| s[5,2] }
#=> {"01"=>["2020-01-05", "2020-01-06", "2020-01-07",
#           "2020-01-08", "2020-01-09"],
#    "02"=>["2020-02-12", "2020-02-13", "2020-02-14"]} 
enum = h.to_a.each
#=> #<Enumerator:...
mon, arr = enum.next
#=> ["01", ["2020-01-05", "2020-01-06", "2020-01-07",
#           "2020-01-08", "2020-01-09"]] 
mon
#=> "01" 
arr
#=> ["2020-01-05", "2020-01-06", "2020-01-07", "2020-01-08",
#    "2020-01-09"] 
mon_name = Date::ABBR_MONTHNAMES[mon.to_i]
#=> "Jan" 
a = arr.map { |s| s[-2,2].to_i }
#=> [5, 6, 7, 8, 9] 
b = a.minmax
#=> [5, 9] 
first_day, last_day = b.map { |d| "%d%s" % [d, ORDINAL[d%10]] }
#=> ["5th", "9th"] 
"%s %s - % s %s" % [mon_name, first_day, mon_name, last_day]
#=> "Jan 5th - Jan 9th" 

mon, arr = enum.next
#=> ["02", ["2020-02-12", "2020-02-13", "2020-02-14"]]

其余步骤类似。

没有其他答案可以处理同一月中的单天和连续几天的多次运行:

dates = ["2020-01-05", "2020-01-06", "2020-01-07",
"2020-01-09",
"2020-01-12", "2020-01-13", "2020-01-14",
"2020-02-12", "2020-02-13", "2020-02-14"].map(&Date.method(:parse))
def ordinalize(num)
ordinals = { 1 => :st, 2 => :nd, 3 => :rd, 4 => :th }
ord_num = (11..13).cover?(num.abs % 100) ? 4 : num.abs
"#{num}#{ordinals[ord_num]}"
end
grouped = dates.sort.chunk_while { |a, b| a + 1 == b }.map(&:minmax).map(&:uniq)
grouped.map do |group|
group.map { |date| date.strftime("%b #{ordinalize(date.day)}") }.join(" - ")
end
# => ["Jan 5th - Jan 7th", "Jan 9th", "Jan 12th - Jan 14th", "Feb 12th - Feb 14th"]

迷你奖金,碰巧不依赖于ActiveSupport

最新更新