反转期间列表

时间:2018-04-23 09:45:43

标签: java time java-8

我有一个句点列表 - 每个句点包含startTime和endTime(作为时间戳)。 我想创建一个列表,其中包含给定范围内的缺失空白。

实施例: 从100500获取给定列表:

  • Range[150, 200]
  • Range[230, 400]

它会产生一个列表:

  • Range[100, 150]
  • Range[200, 230]
  • Range[400, 500]

我创建了一个简单的算法,它迭代我的输入列表并创建有效的结果表,但我想知道我是否可以使用java8时间API做同样的事情,或者是否有一个外部库。

3 个答案:

答案 0 :(得分:4)

使用单个范围边界的列表,您可以使用包含min和max的完整集来构造它:

我正在使用array [int,int],它应该很容易翻译成你的Range对象。

逻辑很简单:只使用范围边界数,制作一个完整的集合,然后制作所有连续边界的对。为此,首先创建所有(不同)数字的排序列表,包括缺失的范围......

List<Integer> flat = Arrays.<int[]>asList(new int[] { 150, 200 }, 
                         new int[] { 230, 400 }).stream()
                          .flatMap(e -> Arrays.asList(e[0], 
                        e[1]).stream()).collect(Collectors.toList());

List<Integer> fullRange = new ArrayList<>();
fullRange.add(100);
fullRange.add(500);
fullRange.addAll(flat);

List<Integer> all = fullRange.stream()
                     .distinct()
                     .sorted()
                     .collect(Collectors.toList());


System.out.println(
      IntStream.range(0, all.size())
               .filter(i -> i < -1 + all.size()) #Excluding the last element
               .mapToObj(index -> Arrays.asList( //You can create Range objects here
                                   all.get(index), 
                                   all.get(index + 1))
                )
               .collect(Collectors.toList()));

输出:

[[100, 150], [150, 200], [200, 230], [230, 400], [400, 500]]

答案 1 :(得分:2)

这是使用我的lib Time4J的解决方案。我假设您的时间戳将被建模为“自Unix纪元以来的毫秒”,但您可以自由使用任何其他类型。 Time4J知道许多不同类型的与日期或时间相关的区间,并提供了各种方法来计算区间的干扰,这里是complement of an interval collection

// define/create your intervals
    MomentInterval i1 =
        MomentInterval.between(Instant.ofEpochMilli(150), Instant.ofEpochMilli(200));
    MomentInterval i2 =
        MomentInterval.between(Instant.ofEpochMilli(230), Instant.ofEpochMilli(400));

// collect the intervals into an interval-collection
    IntervalCollection<Moment> ic =
        IntervalCollection.onMomentAxis().plus(Arrays.asList(i1, i2));

// define/create the outer time window
    MomentInterval window =
        MomentInterval.between(Instant.ofEpochMilli(100), Instant.ofEpochMilli(500));

// create/calculate the complement of the interval collection
    ic.withComplement(window)
      .getIntervals()
      .forEach(
        i ->
            System.out.println(
                "Range[" 
                + i.getStart().getTemporal().toTemporalAccessor().toEpochMilli() 
                + ", "
                + i.getEnd().getTemporal().toTemporalAccessor().toEpochMilli() 
                + "]"
            )
      );
  

范围[100,150]

     

范围[200,230]

     

范围[400,500]

顺便说一句,Time4J使用半开方法进行时刻/瞬时间隔,这意味着排除了这些间隔的结束边界。因此,我宁愿选择开括号“)”而不是“]”,但这里已经密切关注你的问题了。

答案 2 :(得分:0)

另一种解决方案可能如下所示。为此,我定义了一些类和函数。

班级范围

class Range{
  private int start;
  private int end;
}

类RangeInfo

class RangeInfo {
    private List<Range> ranges;
    private int newStart;
    private int newEnd;
  }

<强>功能1:

此函数从两个Range对象创建新的Range对象。

 BiFunction<Range,Range,Range> function1 = (r1,r2)->new Range(r1.getEnd(),r2.getStart());

功能

此函数有两个参数:List (Range[150, 200] and Range[230, 400])Range (100, 500),并返回新范围列表。

BiFunction<List<Range>,Range,List<Range>> function = (r1, pair)->{ // you can use new Pair(100,500) instead of Range object
  result.add(new Range(pair.getStart(),r1.get(0).getStart()));
  IntStream.range(0, r1.size() - 1).mapToObj(i -> function1.apply(r1.get(i), r1.get(i + 1))).forEachOrdered(result::add);
  result.add(new Range(r1.get(r1.size()-1).getEnd(),pair.getEnd()));
  result.addAll(r1);
 return result;
};

最后创建Range并对其进行排序,如下所示。

function.apply(ranges,new Range(100,500))
   .stream()
   .sorted(Comparator.comparingInt(Range::getStart))
   .collect(Collectors.toList());

Demo