【问题标题】:Java 8 stream emitting a stream发出流的 Java 8 流
【发布时间】:2017-03-22 19:45:54
【问题描述】:

我有以下文件格式:

Text1
+ continuation of Text1
+ more continuation of Text1 
Text2
+ continuation of Text2
+ more continuation of Text2
+ even more continuation of Text2

继续以\n+ 标记。 (换行符、加字符、空格作为三个字符串。)续行可以是任意数量的行,包括 0。

我想要以下输出(每个都是用.forEach 打印的一行):

Text1 continuation of Text1 more continuation of Text1 
Text2 continuation of Text2 more continuation of Text2 even more continuation of Text2

我想只使用 Java 流进行转换,最好使用 Collect。有没有办法优雅地做到这一点?

编辑:

另一个更现实的例子:

Lorem ipsum dolor sit amet, consectetur 
+ adipiscing elit, sed do eiusmod tempor incididunt 
+ ut labore et dolore magna aliqua. Ut enim ad minim veniam, 
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex 
+ ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit 
+ esse cillum dolore eu fugiat nulla pariatur. Excepteur sint 
+ occaecat cupidatat non proident, sunt in culpa qui officia 
+ deserunt mollit anim id est laborum.

预期的结果是两行:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

【问题讨论】:

  • 假设第一行总是第一个分隔符并且下一行不包含这个分隔符是否正确?我的意思是continuation of Text1 真的包含Text1 还是只是为了让这个例子更清楚?
  • 不,这只是为了澄清。
  • 1) 所以,第一行总是分隔符?是/否 2) 分隔符不包含在下一行中?是/否 :)
  • 1.不,第一行不是分隔符。它是任意文本。 2. 连接只用“\n+”表示,所以换行加字符加空格。我添加了另一个示例。
  • 这可能是可能的,但不太适合无法引用早期元素并且最好具有无状态映射的流。老式循环是这里更好的选择。

标签: java-8 java-stream


【解决方案1】:

在 Java 9 中,您可以使用

static final Pattern LINE_WITH_CONTINUATION = Pattern.compile("(\\V|\\R\\+)+");

try(Scanner s = new Scanner(file)) {
    s.findAll(LINE_WITH_CONTINUATION)
        .map(m -> m.group().replaceAll("\\R\\+", ""))
        .forEach(System.out::println);
}


由于 Java 8 缺少 Scanner.findAll(Pattern) 方法,您可以添加操作的自定义实现作为解决方法

public static Stream<MatchResult> findAll(Scanner s, Pattern pattern) {
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<MatchResult>(
            1000, Spliterator.ORDERED|Spliterator.NONNULL) {
        public boolean tryAdvance(Consumer<? super MatchResult> action) {
            if(s.findWithinHorizon(pattern, 0)!=null) {
                action.accept(s.match());
                return true;
            }
            else return false;
        }
    }, false);
}

可以像这样使用

try(Scanner s = new Scanner(file)) {
    findAll(s, LINE_WITH_CONTINUATION)
        .map(m -> m.group().replaceAll("\\R\\+", ""))
        .forEach(System.out::println);
}

这将使未来的迁移变得容易。

【讨论】:

    【解决方案2】:

    假设您只按顺序运行它并且真的想要使用流:

     List<String> result = Files.lines(Paths.get("YourPath"))
                .collect(() -> new ArrayList<>(), (list, line) -> {
                    int listSize = list.size();
                    if (line.startsWith("+ ")) {
                        list.set(listSize - 1, list.get(listSize - 1) + line.substring(2));
                    } else {
                        list.add(line);
                    }
                }, (left, right) -> {
                    throw new RuntimeException("Not for parallel processing");
                });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-09
      • 1970-01-01
      • 1970-01-01
      • 2015-11-18
      相关资源
      最近更新 更多