将Stream<Set<Path>>转换为Set<Path>

5

以下是使用Java 8流的代码:

Set<String> getFields( Path xml ) {
   final Set<String> fields = new HashSet<>();
   for( ... ) {
      ...
      fields.add( ... );
      ...
   }
   return fields;
}

void scan() {
   final SortedSet<Path> files = new TreeSet<>();
   final Path root = new File( "....." ).toPath();
   final BiPredicate<Path, BasicFileAttributes> pred =
      (p,a) -> p.toString().toLowerCase().endsWith( ".xml" );
   Files.find( root, 1, pred ).forEach( files::add );
   final SortedSet<String> fields = new TreeSet<>();
   files
      .stream()
      .parallel()
      .map( this::getFields )
      .forEach( s -> fields.addAll( s ));

      // Do something with fields...
}

我想把map( this::getFields )的结果合并,即将一个Stream<Set<Path>>转换成Set<Path>,但我不确定如何正确使用forEach

Jon Skeet回答后编辑内容,以总结评论并编译代码

Stream<String> getFields( Path xml ) {
   final Set<String> fields = new HashSet<>();
   for( ... ) {
      ...
      fields.add( ... );
      ...
   }
   return fields.stream(); // returns a stream to ease integration
}

void scan() {
   final Path root = new File( "....." ).toPath();
   final BiPredicate<Path, BasicFileAttributes> pred =
      (p,a) -> p.toString().toLowerCase().endsWith( ".xml" );
   final SortedSet<Path> files =
      Files
         .find( root, 1, pred )
         .collect( Collectors.toCollection( TreeSet::new ));
   final SortedSet<String> fields =
      files
         .stream()
         .parallel()
         .flatMap( this::getFields )
         .collect( Collectors.toCollection( TreeSet::new ));

      // Do something with fields...
}

两个流可以合并成一个,但是后面会重复使用files
1个回答

6

我猜想您需要使用flatMap而不是map,然后使用Collectors.toCollection创建排序集合:

final SortedSet<String> fields = files
    .stream()
    .parallel()
    .flatMap(x -> getFields(x).stream())
    .collect(Collectors.toCollection(() -> new TreeSet<String>());

(我没有尝试过,所以语法可能会有些问题,但我认为大致符合您的要求。)

总体而言,我建议尝试使用在流操作中创建集合的方法,而不是在最后使用forEach添加所有内容 - 您可以对files执行相同的操作。


1
flatMap需要一个返回流的函数...所以也许可以使用flatMap(x -> getFields(x).stream())?我也没有尝试过。 - ajb
2
.map(this::getFields).flatMap(Set::stream).collect(...) - assylias
@assylias: 仍然使用 collect(Collectors.toCollection(() -> new TreeSet<String>()) 吗?需要两次提到集合好像有点奇怪... - Jon Skeet
3
尝试使用collect(Collectors.toCollection(TreeSet::new)) - Stuart Marks
1
@Stuart:很好,是的。不幸的是现在无法轻松测试它。 - Jon Skeet
谢谢大家,我已经汇编了您们的提议,并将结果代码作为注释放在了最初的问题中。 - Aubin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接