我想要流it (从用户输入)并输出一个特定长度的列表流--有效地将用户的输入批处理成批,然后对其执行其他一些工作。因此,基本上,对于用户输入:1,2,3,4,5,6,7,8,9
,只要我收集到3个数字,我就可以将它分割成这些批<1,2,3> , <4,5,6> , <7,8,9>
,我想为下一个处理步骤创建一个列表。我试图使用lamda和java 8中的流操作来实现这一点,以便更多地了解它。
我能找到的唯一相关示例是这个带有自定义收集器的http://www.nurkiewicz.com/2014/07/grouping-sampling-and-batching-custom.html,它执行与我想要的非常相似的事情--使用收集器的问题是,我不想等待流的结束,而是在准备就绪时处理每一批。
有什么简单的方法吗?在这种操作中使用Java 8流是否不合适?
发布于 2015-11-26 05:11:04
一般来说,使用Java-8StreamAPI解决问题是有问题的。首先,对于并行流来说,将流分割成固定大小的批是不可能的,因为源可能在某个未知偏移量处划分任务,所以在一般情况下,在实际处理所有以前的子任务(这将扼杀整个并行化的想法)之前,您无法知道当前流元素的索引。由于Stream的思想是在并行模式和顺序模式下进行相同的工作,它只是没有将流元素组合成偶数批的方法。有些第三方解决方案通常忽略并行流的存在(如protonpack StreamUtils.windowed
),但通常从一开始就生成批处理而不是转换流比较干净。
第二个问题是,Java-8中没有现成的工具从标准输入中获取数字(或至少是令牌)作为一个流(您只能使用BufferedReader.lines()
获取行)。在Java-9中,随着流支持被添加到Scanner
类(请参阅JDK-8072722),它会更好一些,但是目前您需要执行一些额外的步骤。
最后,如果您成功地创建了数字流批,则需要在标准输入完成后尽快完成它。这是takeWhile
操作的工作,它也将只出现在Java-9中(参见JDK-8071597)。
我可以负担一个涉及我的StreamEx库的解决方案,尽管我仍然不太喜欢它:
Scanner sc = new Scanner(System.in).useDelimiter("[\n\r,\\s]+");
Iterable<String> iterable = () -> sc;
// Supplier which returns Lists of up to 3 numbers from System.in
Supplier<List<Integer>> triples = () -> StreamEx.of(iterable.spliterator())
.map(Integer::valueOf).limit(3).toList();
StreamEx.generate(triples).takeWhile(list -> !list.isEmpty())
// replace with your own stream operations
// they will be executed as soon as three numbers are entered
.forEach(System.out::println);
这里使用的StreamEx的主要特性是StreamEx.takeWhile
,它是Java-9 Stream.takeWhile
的后端。
如果您更喜欢使用jOOL,则会更简单:
Scanner sc = new Scanner(System.in).useDelimiter("[\n\r,\\s]+");
Supplier<List<Integer>> triples = () -> Seq.seq(sc).map(Integer::valueOf).limit(3).toList();
Seq.generate(triples).limitUntil(List::isEmpty)
.forEach(System.out::println);
想法是一样的。Spliterator
创建在这里是不必要的,因为jOOL有Seq.seq(Iterator)
方法。
最后,这里是质子包解决方案。我个人不喜欢这个库,但是解决方案看起来很短,所以有人可能更喜欢它:
import static com.codepoetics.protonpack.StreamUtils.*;
Scanner sc = new Scanner(System.in).useDelimiter("[\n\r,\\s]+");
Stream<List<Integer>> stream = takeUntil(windowed(
stream(() -> sc).map(Integer::valueOf), 3, 3), List::isEmpty);
stream.forEach(System.out::println);
这里的问题是,由于某种原因,它会将批处理延迟到下一批生成。此外,如果它的元素少于3个,则不会创建最后的批处理。这个问题是集群中的fixed,但尚未发布。
https://stackoverflow.com/questions/33925889
复制相似问题