सवाल एक अनुमान से एक धारा सीमित करें


क्या कोई जावा 8 स्ट्रीम ऑपरेशन है जो एक (संभावित रूप से अनंत) को सीमित करता है Stream पहले तत्व तक जो भविष्यवाणी से मेल खाने में विफल रहता है? ऐसा कुछ जो दिखता है (अस्तित्वहीन नहीं) takeWhile नीचे दिए गए उदाहरण में ऑपरेशन और 10 से कम सभी संख्याओं को मुद्रित करेगा?

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

यदि ऐसा कोई ऑपरेशन नहीं है, तो इसे सामान्य तरीके से कार्यान्वित करने का सबसे अच्छा तरीका क्या है?


151
2017-12-23 15:24


मूल


संभावित रूप से उपयोगी जानकारी यहां: stackoverflow.com/q/19803058/248082 - nobeh
सम्बंधित: स्केल ड्रॉप के बराबर - charlie
मैं सोच रहा हूं कि कैसे वास्तुकार कभी भी "हम वास्तव में क्या कर सकते हैं" के माध्यम से प्राप्त कर सकते हैं उपयोग यह "इस उपयोगकेस में भागने के बिना। जावा 8 स्ट्रीम के रूप में केवल मौजूदा डेटास्ट्रक्चर के लिए वास्तव में सहायक हैं: - / - Thorbjørn Ravn Andersen
यह भी देखें स्ट्रीम पर कम () ऑपरेशन को शॉर्ट-सर्किट कैसे करें? - Vadzim


जवाब:


ऐसा ऑपरेशन होना चाहिए मुमकिन जावा 8 के साथ Stream, लेकिन यह आवश्यक रूप से कुशलतापूर्वक नहीं किया जा सकता है - उदाहरण के लिए, आप इस तरह के एक ऑपरेशन को समानांतर रूप से समानांतर नहीं कर सकते हैं, क्योंकि आपको क्रम में तत्वों को देखना है।

एपीआई ऐसा करने का एक आसान तरीका प्रदान नहीं करता है, लेकिन शायद सबसे आसान तरीका क्या है Stream.iterator(), लपेटो Iterator "ले-टाइम" कार्यान्वयन करने के लिए, और उसके बाद वापस जाएं Spliterator और फिर ए Stream। या - शायद - लपेटो Spliteratorहालांकि, इस कार्यान्वयन में इसे वास्तव में विभाजित नहीं किया जा सकता है।

यहां एक अनचाहे कार्यान्वयन है takeWhile पर Spliterator:

static <T> Spliterator<T> takeWhile(
    Spliterator<T> splitr, Predicate<? super T> predicate) {
  return new Spliterators.AbstractSpliterator<T>(splitr.estimateSize(), 0) {
    boolean stillGoing = true;
    @Override public boolean tryAdvance(Consumer<? super T> consumer) {
      if (stillGoing) {
        boolean hadNext = splitr.tryAdvance(elem -> {
          if (predicate.test(elem)) {
            consumer.accept(elem);
          } else {
            stillGoing = false;
          }
        });
        return hadNext && stillGoing;
      }
      return false;
    }
  };
}

static <T> Stream<T> takeWhile(Stream<T> stream, Predicate<? super T> predicate) {
   return StreamSupport.stream(takeWhile(stream.spliterator(), predicate), false);
}

66
2017-12-24 19:09



सिद्धांत रूप में, समानांतर लेना जबकि एक स्टेटलेस भविष्यवाणी के साथ आसान है। समांतर बैचों में स्थिति का मूल्यांकन करें (माना जाता है कि अगर कुछ अतिरिक्त समय निष्पादित किया जाता है तो भविष्यवाणी फेंक नहीं देती है या साइड इफेक्ट नहीं होती है)। यह समस्या रिकर्सिव अपघटन (फोर्क / फ्रेमवर्क में शामिल) के संदर्भ में कर रही है जो स्ट्रीम का उपयोग करती है। असल में, यह धाराएं हैं जो बेहद अक्षम हैं। - Aleksandr Dubinsky
यदि वे स्वैच्छिक समांतरता से इतने व्यस्त नहीं थे तो स्ट्रीम बहुत बेहतर होते। समानांतरता की आवश्यकता केवल उन स्थानों के एक छोटे से अंश में है जहां स्ट्रीम का उपयोग किया जा सकता है। इसके अलावा, अगर ओरेकल ने परफॉर्मेंस के बारे में बहुत कुछ ख्याल रखा है, तो वे जेवीएम जेआईटी ऑटोवेक्टरिज़ बना सकते थे, और डेवलपर्स को परेशान किए बिना, एक बड़ा प्रदर्शन प्रदर्शन प्राप्त कर सकते थे। अब यह स्वैच्छिक समांतरता सही है। - Aleksandr Dubinsky
आपको यह जवाब अब अपडेट करना चाहिए कि जावा 9 जारी किया गया है। - Radiodef


संचालन takeWhile तथा dropWhile जेडीके 9 में जोड़ा गया है। आपका उदाहरण कोड

IntStream
    .iterate(1, n -> n + 1)
    .takeWhile(n -> n < 10)
    .forEach(System.out::println);

जैसा कि आप संकलित करते हैं और जेडीके 9 के तहत दौड़ते हैं, वैसे ही व्यवहार करेंगे।

जेडीके 9 जारी किया गया है। यह यहां डाउनलोड करने के लिए उपलब्ध है: http://jdk.java.net/9/


129
2017-08-31 05:36



जेडीके 9 स्ट्रीम के लिए पूर्वावलोकन दस्तावेज़ों के लिए सीधा लिंक takeWhile/dropWhile: download.java.net/jdk9/docs/api/java/util/stream/Stream.html - Miles
क्या कोई कारण है कि उन्हें बुलाया जाता है takeWhile तथा dropWhile बजाय limitWhile तथा skipWhileमौजूदा एपीआई के साथ स्थिरता के लिए? - Lukas Eder
@LukasEder takeWhile तथा dropWhile स्कैला, पायथन, ग्रोवी, रूबी, हास्केल और क्लोजर में होने वाली बहुत व्यापक हैं। के साथ विषमता skip तथा limit दुर्भाग्यपूर्ण है। शायद skip तथा limit कहा जाना चाहिए था drop तथा take, लेकिन जब तक आप पहले से ही हास्केल से परिचित नहीं हैं, तब तक वे सहज नहीं हैं। - Stuart Marks
@ स्टुअर्टमार्क: मैं इसे समझता हूं dropXXX तथा takeXXX अधिक लोकप्रिय शब्द हैं लेकिन मैं व्यक्तिगत रूप से अधिक एसक्यूएल-एस्क्यू के साथ रह सकता हूं limitXXX तथा skipXXX। मुझे इस नई असमानता को शब्दों की व्यक्तिगत पसंद से ज्यादा भ्रमित लगता है ... :) (बीटीडब्ल्यू: स्कैला भी है drop(int) तथा take(int)) - Lukas Eder


allMatch() एक शॉर्ट-सर्किटिंग फ़ंक्शन है, इसलिए आप इसे प्रसंस्करण रोकने के लिए उपयोग कर सकते हैं। मुख्य नुकसान यह है कि आपको अपना परीक्षण दो बार करना होगा: एक बार यह देखने के लिए कि क्या आपको इसे संसाधित करना चाहिए, और फिर यह देखने के लिए कि क्या जारी रखना है या नहीं।

IntStream
    .iterate(1, n -> n + 1)
    .peek(n->{if (n<10) System.out.println(n);})
    .allMatch(n->n < 10);

47
2017-11-13 22:28



यह मुझे पहले (विधि नाम दिया गया) के लिए अनजान लग रहा था, लेकिन दस्तावेज़ पुष्टि करते हैं उस Stream.allMatch() एक है शॉर्ट-सर्किटिंग ऑपरेशन। तो यह एक अनंत धारा पर भी पूरा हो जाएगा IntStream.iterate()। बेशक, पीछे की ओर, यह एक समझदार अनुकूलन है। - Bailey Parker
यह साफ है, लेकिन मुझे नहीं लगता कि यह बहुत अच्छी तरह से संवाद करता है कि इसका इरादा शरीर का है peek। अगर मुझे अगले महीने इसका सामना करना पड़ा, तो मुझे आश्चर्य होगा कि प्रोग्रामर ने मुझसे पहले क्यों जांच की थी allMatch और फिर जवाब को नजरअंदाज कर दिया। - Joshua Goldberg
इस समाधान का नुकसान यह है कि यह एक बुलियन लौटाता है ताकि आप स्ट्रीम के नतीजों को सामान्य रूप से एकत्र न कर सकें। - neXus


एक फॉलो-अप के रूप में @StuartMarks जवाब। मेरे StreamEx पुस्तकालय में है takeWhile ऑपरेशन जो वर्तमान जेडीके -9 कार्यान्वयन के साथ संगत है। जेडीके-9 के तहत चलते समय यह सिर्फ जेडीके कार्यान्वयन के लिए प्रतिनिधि होगा (के माध्यम से MethodHandle.invokeExact जो वास्तव में तेज़ है)। जेडीके -8 के तहत चलते समय, "पॉलीफिल" कार्यान्वयन का उपयोग किया जाएगा। तो मेरी लाइब्रेरी का उपयोग करके समस्या को हल किया जा सकता है:

IntStreamEx.iterate(1, n -> n + 1)
           .takeWhile(n -> n < 10)
           .forEach(System.out::println);

29
2017-08-31 06:16



आपने StreamEx क्लास के लिए इसे क्यों लागू नहीं किया है? - Someguy
@ सोमेगुई मैंने इसे लागू किया था। - Tagir Valeev


takeWhile द्वारा प्रदान किए गए कार्यों में से एक है प्रोटोनपैक लाइब्रेरी

Stream<Integer> infiniteInts = Stream.iterate(0, i -> i + 1);
Stream<Integer> finiteInts = StreamUtils.takeWhile(infiniteInts, i -> i < 10);

assertThat(finiteInts.collect(Collectors.toList()),
           hasSize(10));

13
2017-09-04 14:55





आप जावा 8 + का उपयोग कर सकते हैं rxjava

import java.util.stream.IntStream;
import rx.Observable;


// Example 1)
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n ->
          {
                System.out.println(n);
                return n < 10;
          }
    ).subscribe() ;


// Example 2
IntStream intStream  = IntStream.iterate(1, n -> n + 1);
Observable.from(() -> intStream.iterator())
    .takeWhile(n -> n < 10)
    .forEach( n -> System.out.println(n));

7
2018-06-02 15:49





अद्यतन: जावा 9 Stream अब एक के साथ आता है takeWhile तरीका।

हैक्स या अन्य समाधान के लिए कोई ज़रूरत नहीं है। बस इसका इस्तेमाल करें!


मुझे यकीन है कि इस पर काफी सुधार किया जा सकता है: (कोई इसे थ्रेड-सुरक्षित बना सकता है)

Stream<Integer> stream = Stream.iterate(0, n -> n + 1);

TakeWhile.stream(stream, n -> n < 10000)
         .forEach(n -> System.out.print((n == 0 ? "" + n : "," + n)));

निश्चित रूप से एक हैक ... सुरुचिपूर्ण नहीं - लेकिन यह काम करता है ~ डी

class TakeWhile<T> implements Iterator<T> {

    private final Iterator<T> iterator;
    private final Predicate<T> predicate;
    private volatile T next;
    private volatile boolean keepGoing = true;

    public TakeWhile(Stream<T> s, Predicate<T> p) {
        this.iterator = s.iterator();
        this.predicate = p;
    }

    @Override
    public boolean hasNext() {
        if (!keepGoing) {
            return false;
        }
        if (next != null) {
            return true;
        }
        if (iterator.hasNext()) {
            next = iterator.next();
            keepGoing = predicate.test(next);
            if (!keepGoing) {
                next = null;
            }
        }
        return next != null;
    }

    @Override
    public T next() {
        if (next == null) {
            if (!hasNext()) {
                throw new NoSuchElementException("Sorry. Nothing for you.");
            }
        }
        T temp = next;
        next = null;
        return temp;
    }

    public static <T> Stream<T> stream(Stream<T> s, Predicate<T> p) {
        TakeWhile tw = new TakeWhile(s, p);
        Spliterator split = Spliterators.spliterator(tw, Integer.MAX_VALUE, Spliterator.ORDERED);
        return StreamSupport.stream(split, false);
    }

}

7
2017-12-25 11:30