在Java8流上执行操作时如何保持状态?

在Java8流上执行操作时如何保持状态?,java,string,java-8,java-stream,Java,String,Java 8,Java Stream,我需要解析一个字符串,该字符串由不同的整数组成,表示某个用户正在或不在看电视时的时段 我首先拆分字符串并将其收集到ArrayList中: final List<String> separated = stream(split(s, "A")) .map(str -> "A" + str) .flatMap(str -> stream(split(str, "B")).map(s2 -> s2.startsWith("A") ? s2 : "B" + s2))

我需要解析一个字符串,该字符串由不同的整数组成,表示某个用户正在或不在看电视时的时段

我首先拆分字符串并将其收集到ArrayList中:

final List<String> separated = stream(split(s, "A"))
  .map(str -> "A" + str)
  .flatMap(str -> stream(split(str, "B")).map(s2 -> s2.startsWith("A") ? s2 : "B" + s2))
  collect(Collectors.toList());
我觉得这是一个巨大的倒退,因为我打破了整个河流管道只是为了回到老学校的每一个

有什么方法可以在一条流管道中完成整个处理吗?我正在考虑创建一个自定义收集器,它将查看集合中的最后一个元素,并在此基础上计算正确的LocalDateTime对象

示例:

输入字符串:A60B80A60,这意味着某人正在观看某个内容60分钟,然后停止观看80分钟,然后再次观看60分钟

因此,我想得到一个包含对象的列表:

1从:0:00到:1:00,观看:真实

2从:1:00到:2:20,观看:错误

3从:2:20到:3:20,观看:正确


每个对象的计算都需要了解前一个对象的相关知识

这不是关于连续对,而是关于收集累积前缀。在函数式编程中,这种操作通常被称为scanLeft,它出现在许多函数式语言中,如。不幸的是,在当前的Java8流API实现中没有它,所以我们只能用forEachOrdered来模拟它。让我们创建一个模型对象:

static class WatchPeriod {
    static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
    final LocalTime start;
    final Duration duration;
    final boolean watched;

    WatchPeriod(LocalTime start, Duration duration, boolean watched) {
        this.start = start;
        this.duration = duration;
        this.watched = watched;
    }

    // Takes string like "A60" and creates WatchPeriod starting from 00:00
    static WatchPeriod forString(String watchPeriod) {
        return new WatchPeriod(LocalTime.of(0, 0),
                   Duration.ofMinutes(Integer.parseInt(watchPeriod.substring(1))),
                   watchPeriod.startsWith("A"));
    }

    // Returns new WatchPeriod which start time is adjusted to start
    // right after the supplied previous period
    WatchPeriod after(WatchPeriod previous) {
        return new WatchPeriod(previous.start.plus(previous.duration), duration, watched);
    }

    @Override
    public String toString() {
        return "from: "+start.format(FORMATTER)+", to: "+
            start.plus(duration).format(FORMATTER)+", watched: "+watched;
    }
}
现在,我们可以将输入字符串(如A60B80A60)拆分为标记A60、B80、A60,将这些标记映射到WatchPeriod对象,然后将它们存储到结果列表中:

String input = "A60B80A60";
List<WatchPeriod> result = new ArrayList<>();
Pattern.compile("(?=[AB])").splitAsStream(input)
    .map(WatchPeriod::forString)
    .forEachOrdered(wp -> result.add(result.isEmpty() ? wp : 
                          wp.after(result.get(result.size()-1))));
result.forEach(System.out::println);
如果您不介意使用第三方库,“我的免费”增强了Stream API,在其他功能中添加了缺少的操作:

String input = "A60B80A60";
List<WatchPeriod> result = StreamEx.split(input, "(?=[AB])")
        .map(WatchPeriod::forString).scanLeft((prev, next) -> next.after(prev));
result.forEach(System.out::println);

结果是一样的。

您能提供输入字符串的示例吗?以及所需的输出?@RobAu,我刚刚编辑了我的答案。重复的问题的答案应该包含足够的信息:
from: 00:00, to: 01:00, watched: true
from: 01:00, to: 02:20, watched: false
from: 02:20, to: 03:20, watched: true
String input = "A60B80A60";
List<WatchPeriod> result = StreamEx.split(input, "(?=[AB])")
        .map(WatchPeriod::forString).scanLeft((prev, next) -> next.after(prev));
result.forEach(System.out::println);