web-dev-qa-db-fra.com

Itérer deux Java-8-Streams ensemble

Je voudrais répéter deux Java-8-Streams ensemble, afin d'avoir à chaque étape de l'itération deux arguments. Quelque chose comme ça, où somefunction produit quelque chose comme Stream<Pair<A,B>>.

Stream<A> as;
Stream<B> bs;
somefunction (as, bs)
  .forEach ((a, b) -> foo (a, b));
// or something like
somefunction (as, bs)
  .forEach ((Pair<A, B> abs) -> foo (abs.left (), abs.right ()));

Je veux savoir si Java fournit quelque chose comme ça, bien qu'il n'y ait pas de Pair dans Java :-( S'il n'y a pas d'API) -Fonctionnement comme ça, existe-t-il une autre façon d'itérer deux flux simultanément?

29
F. Böller
static <A, B> Stream<Pair<A, B>> Zip(Stream<A> as, Stream<B> bs)
{
    Iterator<A> i=as.iterator();
    return bs.filter(x->i.hasNext()).map(b->new Pair<>(i.next(), b));
}

Cela n'offre pas une exécution parallèle, mais pas non plus l'implémentation d'origine Zip.

Et comme F. Böller l'a souligné cela ne fonctionne pas si bs est infini et as ne l'est pas. Pour une solution qui fonctionne pour toutes les combinaisons possibles de flux infinis et finis, un Iterator intermédiaire qui vérifie les deux sources dans la méthode hasNext semble inévitable¹:

static <A, B> Stream<Pair<A,B>> Zip(Stream<A> as, Stream<B> bs) {
    Iterator<A> i1 = as.iterator();
    Iterator<B> i2 = bs.iterator();
    Iterable<Pair<A,B>> i=()->new Iterator<Pair<A,B>>() {
        public boolean hasNext() {
            return i1.hasNext() && i2.hasNext();
        }
        public Pair<A,B> next() {
            return new Pair<A,B>(i1.next(), i2.next());
        }
    };
    return StreamSupport.stream(i.spliterator(), false);
}

Si vous voulez un zipping compatible parallèle, vous devriez considérer la source du Stream. Par exemple. vous pouvez compresser deux ArrayLists (ou n'importe quel RandomAccessList) comme

ArrayList<Foo> l1=new ArrayList<>();
ArrayList<Bar> l2=new ArrayList<>();
IntStream.range(0, Math.min(l1.size(), l2.size()))
         .mapToObj(i->new Pair(l1.get(i), l2.get(i)))
         . …

¹ (sauf si vous implémentez un Spliterator directement)

24
Holger