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

问题描述 投票:132回答:13

在带有lambda b93的JDK 8中,有一个类java.util.stream.Streams.zip in b93可用于压缩流(这在教程Exploring Java8 Lambdas. Part 1 by Dhananjay Nene中有说明)。这个功能:

创建一个惰性和顺序组合Stream,其元素是组合两个流的元素的结果。

然而在b98中,这已经消失了。事实上,在qazxsw poi中甚至无法访问qazxsw poi类。

是否已移动此功能,如果是这样,我如何使用b98简洁地压缩流?

我想到的应用程序是Streams,我在其中替换了zip中的zip功能

具有相当冗长代码的函数(不使用b98中的功能)。

lambda functional-programming java-8 lazy-evaluation java-stream
13个回答
71
投票

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

这里是参考工作代码(自担风险......):

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

1
投票

我所贡献的AOL的scala.collection.immutable.Stream也提供了压缩功能,既可以通过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()); } 实现反应流接口ReactiveSeq,也可以通过StreamUtils通过静态方法向标准Java流提供大量相同的功能。

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));
    }
}

它还提供更广泛的基于Applicative的压缩。例如。

cyclops-react

甚至能够将一个流中的每个项目与另一个流中的每个项目配对

extended Stream implementation

1
投票

使用最新的Guava库(用于 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;
   }

0
投票

这很棒。我不得不将两个流压缩成一个Map,其中一个流是关键,另一个是值

   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")

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


0
投票

如果有人需要这个,Streams库中有final Map<String, String> result = Streams.zip( collection1.stream(), collection2.stream(), AbstractMap.SimpleEntry::new) .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue())); 函数:

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())));

41
投票

zip是static <T> T find(Collection<T> c1, Collection<T> c2, BiPredicate<T, T> pred)提供的功能之一。

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);
}

28
投票

如果你的项目中有Guava,你可以使用protonpack library方法(在Guava 21中添加):

返回一个流,其中每个元素是将streamA和streamB中的每个元素的相应元素传递给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"));

25
投票

使用JDK 8和lambda(qazxsw poi)压缩两个流。

Streams.zip

15
投票

由于我不能设想在索引(列表)以外的集合上使用压缩,而且我是简单的忠实粉丝,这将是我的解决方案:

 public class Streams {
     ...

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

10
投票

您提到的类的方法已移至gist接口本身,转而使用默认方法。但似乎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); } 方法已被删除。也许是因为不清楚不同大小的流的默认行为应该是什么。但实现所需的行为是直截了当的:

<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).mapToObj( i -> {
          return zipper.apply(lista.get(i), listb.get(i));
     });        
}

6
投票

Lazy-Seq库提供zip功能。

Stream

这个库深受zip的启发,旨在提供不可变的,线程安全且易于使用的延迟序列实现,可能是无限的。


6
投票

我谦卑地建议这个实施。结果流被截断为两个输入流中较短的一个。

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);
}

© www.soinside.com 2019 - 2024. All rights reserved.