使用日期列表创建日期范围的哈希数组的最佳方法是什么。例如:如果我在数组中有一个日期列表,如下所示:
['12/11/2014','13/11/2014','14/11/2014','24/11/2014','25/11/2014','26/11/2014','27/11/2014','28/11/2014','29/11/2014','04/12/2014','05/12/2014','06/12/2014','07/12/2014','24/12/2014','25/12/2014','26/12/2014', '28/12/2014', '30/12/2014']
我正在尝试获取类似下面的日期范围哈希数组:
[{:from => '12/11/2014', :to => '14/11/2014'}, {:from => '24/11/2014', :to => '29/11/2014'}, {:from => '04/12/2014', :to => '07/12/2014'}, {:from => '24/12/2014', :to => '26/12/1014'}, {:from => '28/12/2014', :to => '28/12/2014'}, {:from => '30/12/2014', :to => '30/12/2014'}]
Ruby中有什么可用来生成这样的东西吗?感谢。
答案 0 :(得分:3)
Enumerable具有slice_before
方法,可以执行您想要的操作,并添加一些添加的代码。这来自the documentation:
如果块需要在多个元素上维护状态,则可以使用局部变量。例如,可以按如下方式压缩三个或更多个连续增加的数字:
a = [0, 2, 3, 4, 6, 7, 9]
prev = a[0]
p a.slice_before { |e|
prev, prev2 = e, prev
prev2 + 1 != e
}.map { |es|
es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
}.join(",")
#=> "0,2-4,6,7,9"
显然它不是完整的答案,但我不在我的电脑上,它的代码可以完全按照你的意愿行事。
答案 1 :(得分:2)
require 'date'
array = ['12/11/2014','13/11/2014','14/11/2014','24/11/2014','25/11/2014','26/11/2014','27/11/2014','28/11/2014','29/11/2014','04/12/2014','05/12/2014','06/12/2014','07/12/2014','24/12/2014','25/12/2014','26/12/2014', '28/12/2014', '30/12/2014']
dates = array.map { |datestr| [datestr, Date.parse(datestr)] }
prev = nil
ranges = dates.slice_before { |datestr, date|
((prev ? date - prev : 1) != 1).tap { prev = date }
}.map { |dates|
{ from: dates[0][0], to: dates[-1][0] }
}
它比它需要的要复杂一点,因为你使用的是日期字符串而不是日期。此外,使用Range
对象数组而不是哈希值可能更好:
dates = array.map(&Date.method(:parse))
prev = nil
pp dates.slice_before { |date|
((prev ? date - prev : 1) != 1).tap { prev = date }
}.map { |dates| dates[0]..dates[-1] }
答案 2 :(得分:0)
执行此操作的一种方法是使用枚举器。假设你有一个数组:
a = %w[a b d e f i k l m n o t]
#=> ["a", "b", "d", "e", "f", "i", "k", "l", "m", "n", "o", "t"]
然后
arr = [[a.first]]
enum = a[1..-1].to_enum
loop do
e = enum.next
last = arr.last
if last.last.succ == e
last << e
else
arr << [e]
end
end
arr
#=> [["a", "b"], ["d", "e", "f"], ["i"], ["k", "l", "m", "n", "o"], ["t"]]
当尝试超出枚举器StopIteraration
的最后一个元素时, Enumerator#next会引发enum
异常。 Kernel#loop通过突破循环来处理异常。
在您的应用程序中,a
将是Date
个对象的排序数组。您可以使用Enumerable#map和类方法Date::parse将字符串转换为Date
个对象(并在必要时进行排序)。请注意,这适用于响应succ
,Date
个对象为一个(Date#succ)的任何对象集合。