public static List<Interval> mergeSlots(List<Interval> slots) { if (slots.size() <= 1) { return slots; } slots.sort(Comparator.comparing(AbstractInterval::getStart)); boolean isMerged = false; List<Interval> merged = new ArrayList<>(); merged.add(slots.get(0)); for (int i = 1; i < slots.size(); ++i) { Interval first = slots.get(i - 1); Interval second = slots.get(i); if (!second.getStart().isAfter(first.getEnd())) { merged.remove(i - 1); DateTime laterEnding = first.getEnd().isAfter(second.getEnd()) ? first.getEnd() : second.getEnd(); merged.add(new Interval(first.getStart(), laterEnding)); isMerged = true; } else { merged.add(second); } } if (isMerged) { merged = mergeSlots(merged); } // Nothing to merge anymore return merged; }
/** * Collect all subintervals of an interval list of a grain bucketed size which are subintervals of another supply * list of intervals. * * @param supplyIntervals The interval collection to match bucketedIntervals against * @param bucketedIntervals The grain bucketed intervals to collect if they overlap the supply * @param granularity Grain at which to split the bucketingIntervals * * @return a simplified list of subintervals of the bucketedIntervals list */ public static SimplifiedIntervalList collectBucketedIntervalsIntersectingIntervalList( SimplifiedIntervalList supplyIntervals, SimplifiedIntervalList bucketedIntervals, Granularity granularity ) { // Stream the from intervals, split by grain Iterable<Interval> bucketedIterable = granularity.intervalsIterable(bucketedIntervals); // Predicate to find buckets which overlap Predicate<Interval> isIntersecting = new SimplifiedIntervalList.SkippingIntervalPredicate( supplyIntervals, AbstractInterval::overlaps, false ); return StreamSupport.stream(bucketedIterable.spliterator(), false) .filter(isIntersecting) .collect(SimplifiedIntervalList.getCollector()); }