使用带有lambda的JDK8压缩stream(java.util.stream.Streams.zip)

在带有lambda b93的JDK 8中,在b93中有一个java.util.stream.Streams.zip类,可用于压缩stream(这在“ 探索Java8 Lambdas第1部分”中由Dhananjay Nene说明 )。 这个function:

创build一个惰性的顺序组合stream,其元素是组合两个stream的元素的结果。

然而在B98中这个消失了。 事实上Streams类在b98的java.util.stream中甚至是不可访问的。

这个function是否已经被移动,如果是的话,我应该如何使用b98简洁地压缩数据stream?

我想到的应用程序是在这个沉的java实现 ,我在那里取代了zip的function

  • static <T> boolean every(Collection<T> c1, Collection<T> c2, BiPredicate<T, T> pred)
  • static <T> T find(Collection<T> c1, Collection<T> c2, BiPredicate<T, T> pred)

function相当详细的代码(它不使用b98的function)。

我也需要这个,所以我只是从b93的源代码,并把它放在一个“util”类。 我不得不稍微修改它以使用当前的API。

参考这里的工作代码(承担您自己的风险…):

 public static<A, B, C> Stream<C> zip(Stream<? extends A> a, Stream<? extends B> b, BiFunction<? super A, ? super B, ? extends C> zipper) { Objects.requireNonNull(zipper); Spliterator<? extends A> aSpliterator = Objects.requireNonNull(a).spliterator(); Spliterator<? extends B> bSpliterator = Objects.requireNonNull(b).spliterator(); // Zipping looses DISTINCT and SORTED characteristics int characteristics = aSpliterator.characteristics() & bSpliterator.characteristics() & ~(Spliterator.DISTINCT | Spliterator.SORTED); long zipSize = ((characteristics & Spliterator.SIZED) != 0) ? Math.min(aSpliterator.getExactSizeIfKnown(), bSpliterator.getExactSizeIfKnown()) : -1; Iterator<A> aIterator = Spliterators.iterator(aSpliterator); Iterator<B> bIterator = Spliterators.iterator(bSpliterator); Iterator<C> cIterator = new Iterator<C>() { @Override public boolean hasNext() { return aIterator.hasNext() && bIterator.hasNext(); } @Override public C next() { return zipper.apply(aIterator.next(), bIterator.next()); } }; Spliterator<C> split = Spliterators.spliterator(cIterator, zipSize, characteristics); return (a.isParallel() || b.isParallel()) ? StreamSupport.stream(split, true) : StreamSupport.stream(split, false); } 

zip是protonpack库提供的function之一。

 Stream<String> streamA = Stream.of("A", "B", "C"); Stream<String> streamB = Stream.of("Apple", "Banana", "Carrot", "Doughnut"); List<String> zipped = StreamUtils.zip(streamA, streamB, (a, b) -> a + " is for " + b) .collect(Collectors.toList()); assertThat(zipped, contains("A is for Apple", "B is for Banana", "C is for Carrot")); 

使用带有lambda( gist )的JDK8压缩两个stream。

 public static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) { final Iterator<A> iteratorA = streamA.iterator(); final Iterator<B> iteratorB = streamB.iterator(); final Iterator<C> iteratorC = new Iterator<C>() { @Override public boolean hasNext() { return iteratorA.hasNext() && iteratorB.hasNext(); } @Override public C next() { return zipper.apply(iteratorA.next(), iteratorB.next()); } }; final boolean parallel = streamA.isParallel() || streamB.isParallel(); return iteratorToFiniteStream(iteratorC, parallel); } public static <T> Stream<T> iteratorToFiniteStream(Iterator<T> iterator, boolean parallel) { final Iterable<T> iterable = () -> iterator; return StreamSupport.stream(iterable.spliterator(), parallel); } 

你提到的类的方法已经被转移到Stream接口本身,转而使用默认的方法。 但似乎zip方法已被删除。 也许是因为不清楚不同大小的stream的默认行为应该是什么。 但是实施期望的行为是直截了当的:

 static <T> boolean every( Collection<T> c1, Collection<T> c2, BiPredicate<T, T> pred) { Iterator<T> it=c2.iterator(); return c1.stream().allMatch(x->!it.hasNext()||pred.test(x, it.next())); } static <T> T find(Collection<T> c1, Collection<T> c2, BiPredicate<T, T> pred) { Iterator<T> it=c2.iterator(); return c1.stream().filter(x->it.hasNext()&&pred.test(x, it.next())) .findFirst().orElse(null); } 

如果您的项目中有番石榴,您可以使用Streams.zip方法(已在Guava 21中添加):

返回一个stream,其中每个元素是将streamA和streamB中的每个的相应元素传递给函数的结果。 结果stream将只与两个inputstream中较短的一样长。 如果一个stream更长,其额外的元素将被忽略。 生成的stream不能有效地分割。 这可能会损害并行性能。

  public class Streams { ... public static <A, B, R> Stream<R> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<? super A, ? super B, R> function) { ... } } 

Lazy-Seq库提供zipfunction。

https://github.com/nurkiewicz/LazySeq

该库深受scala.collection.immutable.Stream启发,旨在提供不可变,线程安全和易于使用的懒惰序列实现,可能是无限的。

由于我不能想象使用压缩索引(列表)以外的集合,我是一个简单的大爱好者,这将是我的解决scheme:

 <A,B,C> Stream<C> zipped(List<A> lista, List<B> listb, BiFunction<A,B,C> zipper){ int shortestLength = Math.min(lista.size(),listb.size()); return IntStream.range(0,shortestLength).mapToObject( i -> { return zipper.apply(lista.get(i), listb.get(i)); }); } 
 public class Tuple<S,T> { private final S object1; private final T object2; public Tuple(S object1, T object2) { this.object1 = object1; this.object2 = object2; } public S getObject1() { return object1; } public T getObject2() { return object2; } } public class StreamUtils { private StreamUtils() { } public static <T> Stream<Tuple<Integer,T>> zipWithIndex(Stream<T> stream) { Stream<Integer> integerStream = IntStream.range(0, Integer.MAX_VALUE).boxed(); Iterator<Integer> integerIterator = integerStream.iterator(); return stream.map(x -> new Tuple<>(integerIterator.next(), x)); } } 

AOL的独眼巨人反应 ,我贡献,还提供了压缩function,通过扩展stream实现 ,也实现反应stream界面ReactiveSeq,并通过StreamUtils,通过静态方法提供了许多相同的function标准的Javastream。

  List<Tuple2<Integer,Integer>> list = ReactiveSeq.of(1,2,3,4,5,6) .zip(Stream.of(100,200,300,400)); List<Tuple2<Integer,Integer>> list = StreamUtils.zip(Stream.of(1,2,3,4,5,6), Stream.of(100,200,300,400)); 

它还提供了更广泛的基于应用的压缩。 例如

  ReactiveSeq.of("a","b","c") .ap3(this::concat) .ap(of("1","2","3")) .ap(of(".","?","!")) .toList(); //List("a1.","b2?","c3!"); private String concat(String a, String b, String c){ return a+b+c; } 

甚至可以将每个物品与另一个物品中的每个物品配对

  ReactiveSeq.of("a","b","c") .forEach2(str->Stream.of(str+"!","2"), a->b->a+"_"+b); //ReactiveSeq("a_a!","a_2","b_b!","b_2","c_c!","c2") 

这很棒。 我必须将两个stream压缩成一个Map,其中一个stream是关键,另一个是值

 Stream<String> streamA = Stream.of("A", "B", "C"); Stream<String> streamB = Stream.of("Apple", "Banana", "Carrot", "Doughnut"); final Stream<Map.Entry<String, String>> s = StreamUtils.zip(streamA, streamB, (a, b) -> { final Map.Entry<String, String> entry = new AbstractMap.SimpleEntry<String, String>(a, b); return entry; }); System.out.println(s.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()))); 

输出:{A =苹果,B =香蕉,C =胡萝卜}

我虚心地build议这个实现。 结果stream被截断为两个inputstream中较短的一个。

 public static <L, R, T> Stream<T> zip(Stream<L> leftStream, Stream<R> rightStream, BiFunction<L, R, T> combiner) { Spliterator<L> lefts = leftStream.spliterator(); Spliterator<R> rights = rightStream.spliterator(); return StreamSupport.stream(new AbstractSpliterator<T>(Long.min(lefts.estimateSize(), rights.estimateSize()), lefts.characteristics() & rights.characteristics()) { @Override public boolean tryAdvance(Consumer<? super T> action) { return lefts.tryAdvance(left->rights.tryAdvance(right->action.accept(combiner.apply(left, right)))); } }, leftStream.isParallel() || rightStream.isParallel()); }