将流转换为滑动窗口的推荐方法是什么?
例如,在Ruby中你可以使用each_cons:
irb(main):020:0> [1,2,3,4].each_cons(2) { |x| puts x.inspect } [1, 2] [2, 3] [3, 4] => nil irb(main):021:0> [1,2,3,4].each_cons(3) { |x| puts x.inspect } [1, 2, 3] [2, 3, 4] => nil
在Guava中,我发现只有Iterators#partition,它是相关的但没有滑动窗口:
final Iterator> partition = Iterators.partition(IntStream.range(1, 5).iterator(), 3); partition.forEachRemaining(System.out::println); --> [1, 2, 3] [4]
Tagir Valeev.. 17
API中没有这样的功能,因为它支持顺序和并行处理,并且很难为任意流源提供滑动窗口函数的有效并行处理(即使是高效的并行处理对很难,我实现了它,所以我知道).
但是,如果您的源是List
快速随机访问,您可以使用subList()
方法来获得所需的行为,如下所示:
public staticStream > sliding(List
list, int size) { if(size > list.size()) return Stream.empty(); return IntStream.range(0, list.size()-size+1) .mapToObj(start -> list.subList(start, start+size)); }
类似的方法实际上可以在我的StreamEx库中找到:参见StreamEx.ofSubLists()
.
还有一些其他第三方解决方案不关心并行处理,并使用一些内部缓冲区提供滑动功能.例如,质子包StreamUtils.windowed
.
API中没有这样的功能,因为它支持顺序和并行处理,并且很难为任意流源提供滑动窗口函数的有效并行处理(即使是高效的并行处理对很难,我实现了它,所以我知道).
但是,如果您的源是List
快速随机访问,您可以使用subList()
方法来获得所需的行为,如下所示:
public staticStream > sliding(List
list, int size) { if(size > list.size()) return Stream.empty(); return IntStream.range(0, list.size()-size+1) .mapToObj(start -> list.subList(start, start+size)); }
类似的方法实际上可以在我的StreamEx库中找到:参见StreamEx.ofSubLists()
.
还有一些其他第三方解决方案不关心并行处理,并使用一些内部缓冲区提供滑动功能.例如,质子包StreamUtils.windowed
.
如果您愿意使用第三方库而不需要并行性,那么jOOλ提供SQL风格的窗口函数如下
int n = 2;
System.out.println(
Seq.of(1, 2, 3, 4)
.window(0, n - 1)
.filter(w -> w.count() == n)
.map(w -> w.window().toList())
.toList()
);
生产
[[1, 2], [2, 3], [3, 4]]
和
int n = 3;
System.out.println(
Seq.of(1, 2, 3, 4)
.window(0, n - 1)
.filter(w -> w.count() == n)
.map(w -> w.window().toList())
.toList()
);
生产
[[1, 2, 3], [2, 3, 4]]
这是一篇关于它是如何工作的博客文章.
免责声明:我为jOOλ背后的公司工作
另一个选项cyclops -react建立在jOOλ的Seq接口(和JDK 8 Stream)之上,但简单反应构建了并发/并行性(如果这对您很重要 - 通过创建Streams of Futures).
你可以使用Lukas强大的窗口函数和任何一个库(因为我们扩展了令人敬畏的jOOλ),但也有一个滑动算子,我认为在这种情况下简化了事情并且适合在无限流中使用(即它不消耗流,但在它们流过时缓冲值).
使用ReactiveSeq,它看起来像这样 -
ReactiveSeq.of(1, 2, 3, 4) .sliding(2) .forEach(System.out::println);
使用LazyFutureStream 可能看起来像下面的示例 -
LazyFutureStream.iterate(1,i->i+1) .sliding(3,2) //lists of 3, increment 2 .forEach(System.out::println);
在cyclops-streams StreamUtils类中还提供了用于在java.util.stream.Stream上创建滑动视图的Equivalant静态方法.
StreamUtils.sliding(Stream.of(1,2,3,4),2) .map(Pair::new);
如果您想直接使用每个滑动视图,可以使用返回List Transformer的slidingT运算符.例如,要为每个滑动视图中的每个元素添加一个数字,然后将每个滑动窗口减少为我们可以执行的元素之和: -
ReactiveSeqwindowsSummed = ReactiveSeq.fromIterable(data) .slidingT(3) .map(a->a+toAdd) .reduce(0,(a,b)->a+b) .stream();
免责声明:我为独眼巨人反应后的公司工作