将一系列连续日期拆分为相隔十天以上的组

时间:2017-09-08 01:06:32

标签: ruby-on-rails ruby

我想通过引入一个分割来分割以下数组,其中日期的差异是> 10天:

dates = [Date.parse('2017-06-26'), Date.parse('2017-07-04'), Date.parse('2017-11-30')]
#=> [Mon, 26 Jun 2017, Tue, 04 Jul 2017, Thu, 30 Nov 2017]

结果应如下:

[[Mon, 26 Jun 2017, Tue, 04 Jul 2017], [Thu, 30 Nov 2017]]

到目前为止,我有一个非常程序化的方法。它接受要分割的数组作为参数,不同组成员之间的最小差异,以及要评估以获得差异的属性。 (对于我的Date对象数组,我会留下最后一个参数,因为用于确定差异的值只是Date本身)

def split_by_attribute_diff array, split_size, attribute = :itself    
  groups = []
  current_group = []
  previous = current = nil
  array.sort_by(&attribute).each do |e|
    previous = current
    current = e
    if previous && current.send(attribute) - previous.send(attribute) > split_size
      if current_group.count > 0
        groups << current_group
        current_group = []
      end
    end
    current_group << current
  end
  if current_group.count > 0
    groups << current_group
  end

  groups
end

我喜欢这种方法的方法是1)它的工作原理,2)算法复杂度只是sort_by的算法 - 在数组排序后,它只被遍历一次。 我想我唯一不喜欢的是它看起来应该更简单。是否有更多的Ruby-ish方法来完成我在这里所做的事情?

2 个答案:

答案 0 :(得分:3)

如果你正确利用Ruby中的Enumerable库,尤其是chunk_while,那么它并不是很难,这是专门用于根据逻辑测试将数组分成小块的:

require 'date'

dates = %w[
  2017-06-26
  2017-07-04
  2017-11-21
  2017-11-30
  2017-12-30
].map { |d| Date.parse(d) }

r = dates.chunk_while do |a,b|
  a + 10 > b
end

r.to_a.map { |a| a.map { |d| d.strftime('%Y-%m-%d') } }
# => [["2017-06-26", "2017-07-04"], ["2017-11-21", "2017-11-30"], ["2017-12-30"]]

答案 1 :(得分:1)

我的偏好是使用Enumerable#chunk_while(v2.3中的新增内容)或Enumerable#slice_when(v2.2中的新内容)来解决此问题和类似问题。但是,如果必须支持2.2之前的Ruby版本,则可以使用类似于以下的方法。

require 'date'

def group_em(dates)
  fmt = '%Y-%m-%d'
  dates.each_with_object([[]]) do |d,a|
    if a.last.empty? || Date.strptime(d,fmt) <= Date.strptime(a.last.last,fmt) + 10
      a.last << d
    else
      a << [d]
    end
  end
end

group_em %w| 2017-06-26 2017-07-04 2017-11-21 2017-11-30 2017-12-30 |
  #=> [["2017-06-26", "2017-07-04"], ["2017-11-21", "2017-11-30"], ["2017-12-30"]]