it-swarm.dev

تدفقات الملفات المضغوطة باستخدام JDK8 مع lambda (Java.util.stream.Streams.Zip)

في JDK 8 مع lambda b93 ، كان هناك فئة Java.util.stream.Streams.Zip في b93 والتي يمكن استخدامها لتدفقات Zip (هذا موضح في البرنامج التعليمي استكشاف Java8 Lambdas. الجزء 1 من Dhananjay Nene. ). هذه الوظيفة:

يخلق دفقًا مترابطًا كسولًا ومتسلسلًا تكون عناصره نتيجة للجمع بين عناصر دفقين.

لكن في b98 هذا قد اختفى. في الواقع ، لا يمكن الوصول إلى فئة Streams في Java.util.stream in b98 .

هل تم نقل هذه الوظيفة ، وإذا كان الأمر كذلك ، فكيف يمكنني الرمز البريدي للتدفقات بإيجاز باستخدام b98؟

التطبيق الذي يدور في ذهني هو في تطبيق 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).

133
artella

كنت بحاجة إلى هذا أيضًا ، لذا أخذت الشفرة المصدرية من b93 وأضعتها في صف "use". اضطررت إلى تعديله قليلاً للعمل مع 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);
}
71
siki

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"));
41
Dominic Fox

إذا كان لديك Guava في مشروعك ، يمكنك استخدام Streams.Zip الطريقة (تمت إضافته في Guava 21):

إرجاع دفق يكون فيه كل عنصر نتيجة لتمرير العنصر المقابل من كل من دفق streamB و 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) {
         ...
     }
 }
27
ZhekaKozlov

ضغط مسارين باستخدام JDK8 مع lambda ( 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);
}
24
Karol Król

نظرًا لأنني لا أستطيع تصور استخدام أي ضغط على المجموعات بخلاف المجموعات المفهرسة (قوائم) ، وأنا معجب كبير بالبساطة ، فإن هذا سيكون حالي:

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

لقد تم نقل أساليب الفئة التي ذكرتها إلى واجهة 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);
}
10
Holger

توفر مكتبة Lazy-Seq وظائف Zip.

https://github.com/nurkiewicz/LazySeq

هذه المكتبة مستوحاة بشكل كبير من scala.collection.immutable.Stream وتهدف إلى توفير تطبيق تسلسل كسول ثابت وغير آمن وسهل الاستخدام ، وربما لا نهائي.

6
Nick Siderakis

أقترح بكل تواضع هذا التنفيذ. يتم اقتطاع الدفق الناتج إلى أقصر تياري الإدخال.

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());
}
5
Doradus
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));
    }
}
1
robby_pelssers

باستخدام أحدث مكتبة Guava (لفئة Streams) ، يجب أن تكون قادرًا على القيام بذلك

final Map<String, String> result = 
    Streams.Zip(
        collection1.stream(), 
        collection2.stream(), 
        AbstractMap.SimpleEntry::new)
    .collect(Collectors.toMap(e -> e.getKey(), e  -> e.getValue()));
1
Dan Borza

AOL's cyclops-react ، التي أساهم فيها ، توفر أيضًا وظائف zip ، سواء من خلال تنفيذ Stream ممتد ، والذي يقوم أيضًا بتنفيذ واجهة تدفقات رد الفعل ReactiveSeq ، وعبر StreamUtils الذي يوفر الكثير من نفس الوظيفة عبر طرق ثابتة لتدفقات Java القياسية.

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

كما يوفر المزيد من تطبيق zip المعمول به. مثلا.

   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")
1
John McClean

هذا عظيم. اضطررت إلى الرمز البريدي تدفقات اثنين في خريطة مع تيار واحد هو المفتاح والآخر هو القيمة

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 = Apple ، B = موز ، C = جزر}

0
Gnana

إذا احتاج أي شخص إلى ذلك بعد ، فهناك وظيفة StreamEx.zipWith في streamex library:

StreamEx<String> givenNames = StreamEx.of("Leo", "Fyodor")
StreamEx<String> familyNames = StreamEx.of("Tolstoy", "Dostoevsky")
StreamEx<String> fullNames = givenNames.zipWith(familyNames, (gn, fn) -> gn + " " + fn);

fullNames.forEach(System.out::println);  // prints: "Leo Tolstoy\nFyodor Dostoevsky\n"
0
const.grigoryev