拆分重叠并添加缺失的间隔

Split overlapping and add missing intervals

我有一组 [startdate,enddate] 间隔,它们可以重叠并包含间隙。 我的目标是有一个连续的新间隔列表,没有间隔,也没有任何重叠的日期。

范围示例:

[-----------------------------------A-----------------------]
[-B]
   [-C]
      [D]
                  [-----E-----]
                              [-----F----]
                                                                    [-----G-----]                

A [2009-01-01 - 2014-01-01]     ~5 years
B [2009-01-01 - 2009-01-02]     2 days
C [2009-01-02 - 2009-01-03]     2 days
D [2009-01-04 - 2009-01-04]     1 day
E [2010-01-01 - 2011-01-01]     ~1 year
F [2011-01-01 - 2012-01-01]     ~1 year, a gap after this interval
G [2015-01-01 - 2016-01-01]     ~1 year

我期望的是这个新的间隔列表:

[2009-01-01 - 2009-01-01]
[2009-01-02 - 2009-01-02]
[2009-01-03 - 2009-01-03]
[2009-01-04 - 2009-01-04]
[2009-01-05 - 2009-12-31]
[2010-01-01 - 2010-12-31]
[2011-01-01 - 2012-01-01]
[2012-01-02 - 2014-01-01]
[2014-01-02 - 2014-12-31]
[2015-01-01 - 2016-01-01]

因此,对于间隙,添加了新的间隔。具有相同开始日期和结束日期的间隔是完全有效的,应该这样处理。

我非常坚持实现这一目标的最佳方式,甚至在以有效的方式实现这一点之前:(

关于如何在 Java 中执行此操作的任何想法?

首先,按开始日期对它们进行排序。

然后迭代它们,然后将以下所有内容与下一个进行比较:

  • 如果curr.end >= next.start那么curr.end = next.start - 1

  • 如果curr.end < curr.start则删除

  • 如果 curr.end < next.start - 1 然后添加新的:

    new.start = curr.end + 1
    new.end = next.start - 1
    

同时跟踪最大结束日期(更新前),如果 max(end) > last.end 然后添加新的:

new.start = last.end + 1
new.end = max(end)

您可以尝试 range-package of my library Time4J 并使用此代码:

DateInterval a = DateInterval.between(PlainDate.of(2009, 1, 1), PlainDate.of(2014, 1, 1));
DateInterval b = DateInterval.between(PlainDate.of(2009, 1, 1), PlainDate.of(2009, 1, 2));
DateInterval c = DateInterval.between(PlainDate.of(2009, 1, 2), PlainDate.of(2009, 1, 3));
DateInterval d = DateInterval.between(PlainDate.of(2009, 1, 4), PlainDate.of(2009, 1, 4));
DateInterval e = DateInterval.between(PlainDate.of(2010, 1, 1), PlainDate.of(2011, 1, 1));
DateInterval f = DateInterval.between(PlainDate.of(2011, 1, 1), PlainDate.of(2012, 1, 1));
DateInterval g = DateInterval.between(PlainDate.of(2015, 1, 1), PlainDate.of(2016, 1, 1));

List<DateInterval> intervals = Arrays.asList(a, b, c, d, e, f, g);

IntervalCollection<PlainDate> icoll = IntervalCollection.onDateAxis().plus(intervals);

for (ChronoInterval<PlainDate> gap : icoll.withGaps().getIntervals()) {
    icoll = icoll.plus(gap);
}

System.out.println(icoll.withSplits());

[2009-01-01/2009-01-01],
[2009-01-02/2009-01-02],
[2009-01-03/2009-01-03],
[2009-01-04/2009-01-04],
[2009-01-05/2009-12-31],
[2010-01-01/2010-12-31],
[2011-01-01/2011-01-01],
[2011-01-02/2012-01-01],
[2012-01-02/2014-01-01],
[2014-01-02/2014-12-31],
[2015-01-01/2016-01-01]

备注您的预期结果:

你的说法

My goal is to have a continuous new list of intervals, without gaps and without any overlapping dates.

是用上面的代码实现的。在拆分之前,将间隙作为正常间隔添加到整个间隔集合中。默认情况下(可配置),Time4J 中的所有日期间隔都作为闭合间隔处理。这意味着例如像“[2009-01-01/2009-01-01]”这样的间隔只包含一天(正如您在预期间隔列表的第一个条目中显示的那样)。

然而,你似乎没想到间隔“[2011-01-01/2011-01-01]”,只是这个日期(间隔只有一天)是间隔之间的重叠区域E + F 并且也应该出现在您的预期间隔列表中。

关于与 Java-8 的互操作性:

您还可以在类型 net.time4j.PlainDatejava.time.LocalDate 之间应用 toTemporalAccessor() or from(LocalDate) 等直接转换方法。