【问题标题】:Apply reduction only if certain condition is met仅在满足特定条件时应用减少
【发布时间】:2019-05-06 06:18:46
【问题描述】:

有没有办法让 Stream 的 reduce() 方法的“减少”是可选的?

我想遍历一个周期列表并加入重叠的周期,如果它们不重叠,则保持两个周期:

interface Period {
    boolean overlaps(Period other);
}


List<Period> periods = new ArrayList<>();

periods.stream().reduce(new BinaryOperator<Period>() {
    @Override
    public Period apply(Period period, Period period2) {
        if (period.overlaps(period2)){
            // join period and period2 into period.
        }else{
            "return both"
            // don't reduce and maintain period and period2 in the list.
        }
        return null;
    }
});

【问题讨论】:

  • Period 只是我创建的一个界面,用于演示我将把它放入问题中的代码。
  • reduce() 旨在将流的所有元素合并为一个。你不能同时返回。不过,您可以创建自定义收集器。
  • 但是我如何创建一个自定义收集器来评估 list[x] 和 list[x+1]?
  • @shmosel 是的,我对其进行排序以验证期间
  • 我会用 index 做一个 for

标签: java java-8 java-stream reduce


【解决方案1】:

我认为您不能仅使用流轻松做到这一点。使用Guava ranges,您可以执行以下操作:

periods.stream()
        .map(p -> Range.closedOpen(p.getStart(), p.getEnd()))
        .collect(TreeRangeSet::<Integer>create, RangeSet::add, RangeSet::addAll)
        .asRanges()
        .stream()
        .map(r -> new PeriodImpl(r.lowerEndpoint(), r.upperEndpoint()))
        .collect(Collectors.toList());

这假定类结构如下所示,但您可以根据需要进行调整:

interface Period {
    int getStart();
    int getEnd();
}

class PeriodImpl implements Period {
    PeriodImpl(int start, int end) {
        //...
    }
    //...
}

【讨论】:

    【解决方案2】:

    试试StreamEx中提供的collapse

    // Here I use Range type provided in Google Guava for test.
    List<Range<Integer>> list = Arrays.asList(Range.openClosed(1, 3), Range.openClosed(2, 4), Range.closed(5, 5));
    
    StreamEx.of(list)
        .collapse(Range::isConnected, Range::span)
        .forEach(System.out::println);
    // (1..4]
    // [5..5]
    

    【讨论】:

    • 这看起来很有趣,但我不能使用外部库
    猜你喜欢
    • 2013-02-21
    • 1970-01-01
    • 2016-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多