【问题标题】:Find holes in Joda-Time intervals在 Joda-Time 间隔中查找漏洞
【发布时间】:2019-04-30 22:05:23
【问题描述】:

我有Joda-Timeintervals的列表

List<Interval> intervals = new ArrayList<Interval>();

还有另一个 Joda-Time 间隔(搜索时间间隔),如下图所示。

我需要编写 Java 函数来及时找到漏洞并返回带有红色间隔的List&lt;Interval&gt;

【问题讨论】:

  • 你有没有尝试过?
  • 您的列表中的间隔是否排序?
  • 我在考虑。我想出的只是多个 for in for 循环。必须有一个更优雅的解决方案。间隔已排序。

标签: java jodatime


【解决方案1】:

建立在 fge 的响应之上 - 以下版本实际上处理了这两种情况(当大间隔大于被搜索间隔的极值时 + 大间隔实际上更小......或更小的情况侧面)

你可以在https://github.com/erfangc/JodaTimeGapFinder.git看到完整的代码和测试

public class DateTimeGapFinder {

    /**
     * Finds gaps on the time line between a list of existing {@link Interval}
     * and a search {@link Interval}
     * 
     * @param existingIntervals
     * @param searchInterval
     * @return The list of gaps
     */
    public List<Interval> findGaps(List<Interval> existingIntervals, Interval searchInterval) {
        List<Interval> gaps = new ArrayList<Interval>();

        DateTime searchStart = searchInterval.getStart();
        DateTime searchEnd = searchInterval.getEnd();

        if (hasNoOverlap(existingIntervals, searchInterval, searchStart, searchEnd)) {
            gaps.add(searchInterval);
            return gaps;
        }

        // create a sub-list that excludes interval which does not overlap with
        // searchInterval
        List<Interval> subExistingList = removeNoneOverlappingIntervals(existingIntervals, searchInterval);
        DateTime subEarliestStart = subExistingList.get(0).getStart();
        DateTime subLatestStop = subExistingList.get(subExistingList.size() - 1).getEnd();

        // in case the searchInterval is wider than the union of the existing
        // include searchInterval.start => earliestExisting.start
        if (searchStart.isBefore(subEarliestStart)) {
            gaps.add(new Interval(searchStart, subEarliestStart));
        }

        // get all the gaps in the existing list
        gaps.addAll(getExistingIntervalGaps(subExistingList));

        // include latestExisting.stop => searchInterval.stop
        if (searchEnd.isAfter(subLatestStop)) {
            gaps.add(new Interval(subLatestStop, searchEnd));
        }
        return gaps;
    }

    private List<Interval> getExistingIntervalGaps(List<Interval> existingList) {
        List<Interval> gaps = new ArrayList<Interval>();
        Interval current = existingList.get(0);
        for (int i = 1; i < existingList.size(); i++) {
            Interval next = existingList.get(i);
            Interval gap = current.gap(next);
            if (gap != null)
                gaps.add(gap);
            current = next;
        }
        return gaps;
    }

    private List<Interval> removeNoneOverlappingIntervals(List<Interval> existingIntervals, Interval searchInterval) {
        List<Interval> subExistingList = new ArrayList<Interval>();
        for (Interval interval : existingIntervals) {
            if (interval.overlaps(searchInterval)) {
                subExistingList.add(interval);
            }
        }
        return subExistingList;
    }

    private boolean hasNoOverlap(List<Interval> existingIntervals, Interval searchInterval, DateTime searchStart, DateTime searchEnd) {
        DateTime earliestStart = existingIntervals.get(0).getStart();
        DateTime latestStop = existingIntervals.get(existingIntervals.size() - 1).getEnd();
        // return the entire search interval if it does not overlap with
        // existing at all
        if (searchEnd.isBefore(earliestStart) || searchStart.isAfter(latestStop)) {
            return true;
        }
        return false;
    }
}

【讨论】:

    【解决方案2】:

    快速浏览一下 Interval API 可以得出以下结论(未测试):

    // SUPPOSED: the big interval is "bigInterval"; the list is "intervals"
    
    // Intervals returned
    List<Interval> ret = new ArrayList<>();
    
    
    Interval gap, current, next;
    
    // First, compute the gaps between the elements in the list
    
    current = intervals.get(0);
    for (int i = 1; i < intervals.size(); i++) {
        next = intervals.get(i);
        gap = current.gap(next);
        if (gap != null)
            ret.add(gap);
        current = next;
    }
    
    // Now, compute the time difference between the starting time of the first interval
    // and the starting time of the "big" interval; add it at the beginning
    
    ReadableInstant start, end;
    
    start = bigInterval.getStart();
    end = intervals.get(0).getStart();
    
    if (start.isBefore(end))
        ret.add(0, new Interval(start, end));
    
    //
    // finally, append the time difference between the ending time of the last interval
    // and the ending time of the "big" interval
    
    // next still contains the last interval
    start = next.getEnd();
    end = bigInterval.getEnd();
    if (start.isBefore(end))
        ret.add(new Interval(start, end));
    
    return ret;
    

    【讨论】:

    • 呃不,等等,有错误
    • 好的,已修复;最后的两个计算是假的
    • 您忽略了一种可能的情况:如果 bigInterval 小于列表中的间隔之一。
    【解决方案3】:

    answer by fge 似乎是正确的,尽管我没有运行未经测试的代码。

    术语“间隙”似乎是您所说的“孔”的更常见术语。

    参见this answer by Katja Christiansen,它很好地利用了Interval 类上的gap 方法。

    Interval gapInterval = interval_X.gap( interval_Y );
    // … Test for null to see whether or a gap exists.
    

    如果它们之间的持续时间不为零,则会返回一个新的 Interval 对象。如果间隔重叠或邻接,则返回 null。请注意,如果您对这些特定条件感兴趣,Interval 类还提供了 overlapabuts 方法。

    当然,您的 Interval 对象集合必须经过排序才能正常工作。

    【讨论】:

    • 我认为这不是 op 想要的。我认为他正在寻找一个与一堆间隔重叠的间隔并找到那些间隙
    • @BrandonLing 不,总体间隔是给定的。请注意问题图表中的红色块是我们要发现的目标,包括两端的红色块。仅当给定较大的拥抱间隔时,这才有意义。第一句还说较大的区间是已知的。
    猜你喜欢
    • 2012-08-15
    • 1970-01-01
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多