[lambda] 람다와 함께 JDK8을 사용하여 압축 스트림 (java.util.stream.Streams.zip)

람다 b93이있는 JDK 8에는 스트림을 압축하는 데 사용할 수 있는 클래스 java.util.stream.Streams.zip이 b93 에 있습니다 ( Dhananjay Nene의 Java8 Lambdas 탐험 1 부 튜토리얼에 설명되어 있음 ). 이 기능 :

요소가 두 스트림의 요소를 결합한 결과 인 지연 및 순차 결합 스트림을 작성합니다.

그러나 b98에서 이것은 사라졌습니다. 실제로 Streams클래스는 b98의 java.util.stream 에서도 액세스 할 수 없습니다 .

이 기능이 이동 되었습니까? 그렇다면 b98을 사용하여 스트림을 간결하게 압축하는 방법은 무엇입니까?

내가 생각한 응용 프로그램 은 Shen 의이 Java 구현에 있으며 , 여기서 Zip 기능을 대체했습니다.

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

다소 장황한 코드가있는 함수 (b98의 기능을 사용하지 않음).



답변

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 라이브러리에서 제공하는 기능 중 하나입니다 .

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


답변

프로젝트에 Guava가있는 경우 Streams.zip 메소드를 사용할 수 있습니다 (Guava 21에 추가됨).

각 요소가 streamA 및 streamB 각각의 해당 요소를 함수에 전달한 결과 인 스트림을 리턴합니다. 결과 스트림은 두 입력 스트림 중 더 짧은 길이입니다. 하나의 스트림이 더 길면 추가 요소는 무시됩니다. 결과 스트림은 효율적으로 분할 할 수 없습니다. 병렬 성능이 저하 될 수 있습니다.

 public class Streams {
     ...

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


답변

lambda ( gist ) 와 함께 JDK8을 사용하여 두 개의 스트림을 압축 합니다.

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


답변

언급 한 클래스의 메소드 Stream는 기본 메소드에 유리하게 인터페이스 자체 로 이동되었습니다 . 그러나 zip방법이 제거 된 것 같습니다 . 다른 크기의 스트림에 대한 기본 동작이 무엇인지 명확하지 않기 때문일 수 있습니다. 그러나 원하는 동작을 구현하는 것은 간단합니다.

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


답변

겸손하게이 구현을 제안합니다. 결과 스트림은 두 입력 스트림 중 짧은 스트림으로 잘립니다.

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