使用ruby从日期列表中创建日期范围数组

时间:2014-11-13 05:00:28

标签: ruby arrays date

使用日期列表创建日期范围的哈希数组的最佳方法是什么。例如:如果我在数组中有一个日期列表,如下所示:

['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中有什么可用来生成这样的东西吗?感谢。

3 个答案:

答案 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个对象(并在必要时进行排序)。请注意,这适用于响应succDate个对象为一个(Date#succ)的任何对象集合。