2012-01-06 72 views
1

比方说,我有红宝石下列日期范围:如何找到在多个日期范围打破了红宝石

星期六,01一月2011..Tue,2011年2月1日

星期三,05一月2011..Thu,2011年2月17日

周三,02二月2011..Tue,2011年3月1日

孙,01月2012..Thu,2012

月05日210

通过什么样的过程,我可以采用所有这四个范围,并获得输出结果,告诉我在2011年3月2日星期三的范围内有一个突破?

编辑 塞尔吉奥是正确的,似乎是没有什么内置的,我可以神交这个像这样:

x = Range.new(Date.parse('2011-01-01'), Date.parse('2011-02-01')) 
r = Range.new(Date.parse('2011-01-05'), Date.parse('2011-02-17')) 
y = Range.new(Date.parse('2011-02-02'), Date.parse('2011-03-01')) 
z = Range.new(Date.parse('2012-01-01'), Date.parse('2012-01-05')) 

ranges = [x,y,z,r] 

dates = ranges.collect!{|r|r.to_a}.flatten!.uniq!.sort! 

dates.delete_if do |date| 
    index = ranges.index(date) 
    next_date = ranges[index + 1] 
    next_date == date + 1 || next_date.nil? 
end 

还在寻找最佳的解决方案,但。

+0

有没有内置的功能做到这一点。试着弄清楚一些事情。 – 2012-01-06 20:23:23

+1

什么是“范围内的突破”?也许你可以把一些有效的Ruby代码放在一起。 – tokland 2012-01-06 20:40:13

+0

好吧,你可能是指“什么日期开始在范围内的差距”?但是如果范围产生了几个缺口,你只需要第一个呢? – tokland 2012-01-06 20:57:40

回答

2

Ruby的Enumerable.chunk在这里很有用。我缩短被检查为简单起见范围,并增加了一个额外的范围,这是不按顺序,以表明它在处理乱序范围:

require 'date' 

date_ranges = [ 
    '01 Jan 2011', '03 Jan 2011', 
    '02 Jan 2011', '04 Jan 2011', 
    '02 Mar 2011', '03 Mar 2011', 
    '01 Jan 2000', '02 Jan 2000' 
].each_slice(2).map{ |dates| 
    Range.new( 
    *dates.map{ |d| 
     Date.parse(d) 
    } 
) 
} 

gaps = date_ranges 
    .inject([]){ |a, d| a |= d.to_a } # accumulate the unique dates in the ranges 
    .sort        # sort to get them in ascending order 
    .each_with_index     # add an offset into the order 
    .chunk{ |d,i| d - i }    # group by the delta 
    .to_a[1 .. -1]      # grab all but the first group 
    .map{ |g,dates| dates.first.first } # strip off the groups and indexes 

puts gaps 

输出:

2011-01-01 
2011-03-02 

因为我增加了失序的范围内,原来的起跑距离现在是一个缺口,就像2011年3月02日那样。

这会给你一个例子什么chunk做:

[1,2,3,4,5].each_with_index.chunk{ |n,i| n-i }.to_a # => [[1, [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]]] 
[1,2, 4,5].each_with_index.chunk{ |n,i| n-i }.to_a # => [[1, [[1, 0], [2, 1]]], [2, [[4, 2], [5, 3]]]] 
0

我将接近那会是这样(完成这个左为exersize读者)方式:

class DateRange 
    def initialize (start, end) 
    ... 
    end 

    def interection (range) 
    # Determine the intersection of the current range and another 
    # Returns either nil or a new DateRange object. 
    ... 
    end 

    def expand (range) 
    # Expand the current range to include the passed in range 
    ... 
    end 
end 

class DateRangeSet 
    include Enumerable 

    def <<(range) 
    # Inspect the current ranges, and any that have an intersection, merge them 
    ... 
    end 

    def each 
    @ranges.each { |r| yield r } 
    end 
end 

假设你input[start,end]数组的数组,像这样:

coll = DateRangeCollection.new 
input.each { |s, e| coll << DateRange.new(s,e) } 
puts "Gaps found!" if coll.to_a.count > 1 

这就是说...也许有一个更简洁的方式?

0

阵列运算:

date_ranges = [ 
    '01 Jan 2011', '03 Jan 2011', 
    '02 Jan 2011', '04 Jan 2011', 
    '02 Mar 2011', '03 Mar 2011', 
    '01 Jan 2000', '02 Jan 2000' 
].each_slice(2).map{ |dates| 
    Range.new( 
    *dates.map{ |d| 
     Date.parse(d) 
    } 
) 
} 

dates = date_ranges.collect{|r| r.to_a}.flatten 

((dates.min..dates.max).to_a - dates).min