एक धारा से क्रमिक जोड़े लीजिए


102

एक स्ट्रीम जैसे { 0, 1, 2, 3, 4 },

मैं इसे कैसे दिए गए रूप में बदल सकता हूं:

{ new Pair(0, 1), new Pair(1, 2), new Pair(2, 3), new Pair(3, 4) }

(यह मानते हुए, मैंने कक्षा जोड़ी को परिभाषित किया है)?

संपादित करें: यह ints या आदिम धाराओं के बारे में कड़ाई से नहीं है। किसी भी प्रकार की धारा के लिए उत्तर सामान्य होना चाहिए।


2
एफपी से शब्द "विभाजन" है, लेकिन मुझे जावा में वांछित शब्दार्थ के साथ एक विधि नहीं मिल रही है। यह एक विधेय पर विभाजन है।
मार्को टोपोलनिक 12

1
आमतौर पर जेडीके 8 में स्प्लिटर को ट्रैवर्सिंग और विभाजन उद्देश्यों के लिए सोचा जाता है। मैं एक उदाहरण के साथ भी आने की कोशिश करूंगा।
ओलपिम्पू पीओपी

list.stream().map(i -> new Pair(i, i+1));
aepurniet 15

2
समान गैर-स्ट्रीम प्रश्नों के लिए, stackoverflow.com/questions/17453022/…
Raedwald

वैसे, कुछ लोग या तो Map.Entryएक जोड़ी वर्ग के रूप में कार्यान्वयन का उपयोग करते हैं । (दी, कुछ लोग इस पर विचार कर सकते हैं कि एक हैक, लेकिन बिल्ट-इन क्लास का उपयोग करना आसान है।)
बेसिल बोर्क

जवाबों:


33

मेरी स्ट्रीमटेक्स लाइब्रेरी जो मानक धाराओं का विस्तार करती है pairMap, सभी स्ट्रीम प्रकारों के लिए एक विधि प्रदान करती है । आदिम धाराओं के लिए यह धारा प्रकार को नहीं बदलता है, लेकिन इसका उपयोग कुछ गणना करने के लिए किया जा सकता है। मतभेदों की गणना करने के लिए सबसे आम उपयोग है:

int[] pairwiseDiffs = IntStreamEx.of(input).pairMap((a, b) -> (b-a)).toArray();

ऑब्जेक्ट स्ट्रीम के लिए आप किसी अन्य ऑब्जेक्ट प्रकार बना सकते हैं। मेरी लाइब्रेरी कोई नई उपयोगकर्ता-दृश्यमान डेटा संरचना प्रदान नहीं करती है, जैसे Pair(वह लाइब्रेरी कॉन्सेप्ट का हिस्सा है)। हालाँकि यदि आपकी अपनी Pairकक्षा है और आप उसका उपयोग करना चाहते हैं, तो आप निम्न कार्य कर सकते हैं:

Stream<Pair> pairs = IntStreamEx.of(input).boxed().pairMap(Pair::new);

या यदि आपके पास पहले से ही कुछ है Stream:

Stream<Pair> pairs = StreamEx.of(stream).pairMap(Pair::new);

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


धन्यवाद! जितना अधिक मैं इस पुस्तकालय का अध्ययन करता हूं, उतना ही मुझे यह पसंद आता है। मैं अंत में धाराओं का उपयोग शुरू कर सकता हूं। ( StreamExऔजार Iterableहुर्रे!)
Aleksandr Dubinsky

अपने उत्तर को 100% पूरा करने के लिए, क्या आप दिखा सकते हैं कि कैसे एक Streamमें लपेटें StreamEx?
अलेक्सांद्र डबलिनस्की

3
@AleksandrDubinsky: बस उपयोग करें StreamEx.of(stream)। अन्य सुविधाजनक स्टैटिक विधियाँ हैं, जिससे Collectionव्यूह Reader, आदि से धारा बनाई जा सकती है ।
टैगिर वलेव

@TagirValeev अनुक्रमिक pairMapधाराओं पर आदेशित है ? वास्तव में, मैं forPairsOrdered () करना चाहूंगा, लेकिन जैसा कि कोई तरीका नहीं है, क्या मैं इसे किसी तरह अनुकरण कर सकता हूं? stream.ordered().forPairs()या stream().pairMap().forEachOrdered()?
अस्कर कल्यकोव

1
@AskarKalykov, pairMapनॉन- इंटरफेरिंग स्टेटलेस मैपर फ़ंक्शन के साथ इंटरमीडिएट ऑपरेशन है, ऑर्डर को इसके लिए उसी तरह निर्दिष्ट नहीं किया जाता है जैसे कि साधारण के लिए mapforPairsविनिर्देश द्वारा अव्यवस्थित है, लेकिन अव्यवस्थित संचालन जिस वास्तविक अनुक्रमिक धाराओं के लिए आदेश दिया है। अच्छा होगा यदि आप अपनी मूल समस्या को अलग संदर्भ के रूप में अलग-अलग स्टैकओवरफ़्लो प्रश्न के रूप में तैयार करें।
तागीर वालेव

74

जावा 8 स्ट्रीम लाइब्रेरी मुख्य रूप से समानांतर प्रसंस्करण के लिए छोटे विखंडू में धाराओं को विभाजित करने की ओर अग्रसर है, इसलिए स्टेटफुल पाइपलाइन चरण काफी सीमित हैं, और वर्तमान स्ट्रीम तत्व का इंडेक्स प्राप्त करने और आसन्न स्ट्रीम तत्वों तक पहुंचने जैसी चीजें समर्थित नहीं हैं।

इन समस्याओं को हल करने का एक विशिष्ट तरीका, कुछ सीमाओं के साथ, निश्चित रूप से, अनुक्रमित द्वारा धारा को ड्राइव करना है और कुछ बेतरतीब-एक्सेस डेटा संरचना में संसाधित होने वाले मानों पर भरोसा करना है, जैसे कि एक ArrayList जिसमें से तत्वों को पुनर्प्राप्त किया जा सकता है। यदि मान में थे arrayList, तो कुछ इस तरह से करके जोड़े उत्पन्न कर सकते हैं:

    IntStream.range(1, arrayList.size())
             .mapToObj(i -> new Pair(arrayList.get(i-1), arrayList.get(i)))
             .forEach(System.out::println);

बेशक सीमा यह है कि इनपुट एक अनंत प्रवाह नहीं हो सकता है। इस पाइपलाइन को समानांतर में चलाया जा सकता है, हालाँकि।


5
"इनपुट एक अनंत स्ट्रीम नहीं हो सकता है।" दरअसल, इनपुट एक स्ट्रीम नहीं हो सकता है। इनपुट ( arrayList) वास्तव में एक संग्रह है, यही कारण है कि मैंने इसे उत्तर के रूप में चिह्नित नहीं किया। (लेकिन अपने सोने बैज पर बधाई!)
Aleksandr Dubinsky

16

यह सुरुचिपूर्ण नहीं है, यह एक हैकिश समाधान है, लेकिन अनंत धाराओं के लिए काम करता है

Stream<Pair> pairStream = Stream.iterate(0, (i) -> i + 1).map( // natural numbers
    new Function<Integer, Pair>() {
        Integer previous;

        @Override
        public Pair apply(Integer integer) {
            Pair pair = null;
            if (previous != null) pair = new Pair(previous, integer);
            previous = integer;
            return pair;
        }
    }).skip(1); // drop first null

अब आप अपनी स्ट्रीम को अपनी इच्छित लंबाई तक सीमित कर सकते हैं

pairStream.limit(1_000_000).forEach(i -> System.out.println(i));

पीएस मुझे उम्मीद है कि बेहतर समाधान, क्लोजर जैसा कुछ है(partition 2 1 stream)


6
कुदोस बताते हैं कि अनाम कक्षाएं लंबोदर के लिए कभी-कभी उपयोगी विकल्प हैं।
अलेक्सांद्र डबिन्सकी

2
मुझे लगता है कि यह सही ढंग से काम नहीं करेगा। parallelStreamडॉक्टर के अनुसार : "सही व्यवहार को बनाए रखने के लिए, इन व्यवहार मानकों को गैर-हस्तक्षेप करना होगा, और ज्यादातर मामलों में स्टेटलेस होना चाहिए"
मिसहादॉफ

14
यह पूरी तरह से स्ट्रीम फ्रेमवर्क के डिजाइन के विपरीत है और मानचित्र एपीआई के अनुबंध का सीधे उल्लंघन करता है, क्योंकि अनाम फ़ंक्शन स्टेटलेस नहीं है । इसे एक समानांतर धारा और अधिक डेटा के साथ चलाने की कोशिश करें ताकि स्ट्रीम फ्रेमवर्क अधिक काम करने वाले धागे बनाता है, और आप परिणाम देखेंगे: जब तक आपके पास पर्याप्त (उत्पादन में?) डेटा नहीं है, तब तक यादृच्छिक यादृच्छिक "त्रुटियों" को पुन: पेश करना और पता लगाना मुश्किल है। यह विनाशकारी हो सकता है।
मारियो रॉसी

4
@AleksandrDubinsky आप सीमा के बारे में गलत हैं / समानांतर होने को छोड़ दें; जेडीके में प्रदान किया गया कार्यान्वयन वास्तव में समानांतर में काम करता है। क्योंकि ऑपरेशन एनकाउंटर ऑर्डर से बंधा हुआ है, इसलिए हो सकता है कि समानांतरीकरण हमेशा एक प्रदर्शन लाभ प्रदान न करे, लेकिन उच्च-क्यू स्थितियों में, यह कर सकता है।
ब्रायन गोएटज

4
@AleksandrDubinsky गलत। यदि धारा अनियंत्रित है (कोई परिभाषित मुठभेड़ क्रम नहीं है, तो यह एक यादृच्छिक तत्व को छोड़ सकता है , इसलिए तार्किक रूप से कोई "पहला" या "nth" तत्व नहीं है, बस तत्व हैं।) लेकिन क्या स्ट्रीम का आदेश दिया गया है या अनियंत्रित है, छोड़ें हमेशा सक्षम है। समानांतर में काम करने के लिए। यदि धारा का आदेश दिया जाता है तो निकालने के लिए बस कम समानता है, लेकिन इसकी अभी भी समानांतर है।
ब्रायन गोएटज

15

मैंने एक स्प्लिटर रेपर लागू किया है जो मूल स्प्लिंटर से प्रत्येक nतत्व लेता है Tऔर उत्पन्न करता है List<T>:

public class ConsecutiveSpliterator<T> implements Spliterator<List<T>> {

    private final Spliterator<T> wrappedSpliterator;

    private final int n;

    private final Deque<T> deque;

    private final Consumer<T> dequeConsumer;

    public ConsecutiveSpliterator(Spliterator<T> wrappedSpliterator, int n) {
        this.wrappedSpliterator = wrappedSpliterator;
        this.n = n;
        this.deque = new ArrayDeque<>();
        this.dequeConsumer = deque::addLast;
    }

    @Override
    public boolean tryAdvance(Consumer<? super List<T>> action) {
        deque.pollFirst();
        fillDeque();
        if (deque.size() == n) {
            List<T> list = new ArrayList<>(deque);
            action.accept(list);
            return true;
        } else {
            return false;
        }
    }

    private void fillDeque() {
        while (deque.size() < n && wrappedSpliterator.tryAdvance(dequeConsumer))
            ;
    }

    @Override
    public Spliterator<List<T>> trySplit() {
        return null;
    }

    @Override
    public long estimateSize() {
        return wrappedSpliterator.estimateSize();
    }

    @Override
    public int characteristics() {
        return wrappedSpliterator.characteristics();
    }
}

एक सतत स्ट्रीम बनाने के लिए निम्नलिखित विधि का उपयोग किया जा सकता है:

public <E> Stream<List<E>> consecutiveStream(Stream<E> stream, int n) {
    Spliterator<E> spliterator = stream.spliterator();
    Spliterator<List<E>> wrapper = new ConsecutiveSpliterator<>(spliterator, n);
    return StreamSupport.stream(wrapper, false);
}

नमूना उपयोग:

consecutiveStream(Stream.of(0, 1, 2, 3, 4, 5), 2)
    .map(list -> new Pair(list.get(0), list.get(1)))
    .forEach(System.out::println);

क्या हर तत्व दो बार दोहराता है?
अलेक्सांद्र डबिन्सकी

नहीं। यह List<E>तत्वों से युक्त एक नई धारा बनाता है । प्रत्येक सूची में nमूल धारा से लगातार तत्व होते हैं । इसे स्वयं जांचें;)
टोमेक रेकवेक

क्या आप अपना उत्तर संशोधित कर सकते हैं ताकि हर तत्व (पहले और अंतिम को छोड़कर) को दोहराया जाए?
११:१३ को अलेक्सांद्र डबिन्सकी

4
+1 मुझे लगता है कि यह अच्छा काम है और इसे विभाजन आकार के अतिरिक्त किसी भी चरण आकार के लिए सामान्यीकृत किया जाना चाहिए। एक (partition size step)फ़ंक्शन की बहुत आवश्यकता है और इसे प्राप्त करने का सबसे अच्छा तरीका है।
मार्को टोपोलनिक

3
ArrayDequeवरीयता के लिए, प्रदर्शन के लिए उपयोग करने पर विचार करें LinkedList
मार्को टोपोलनिक

14

आप इसे Stream.reduce () विधि के साथ कर सकते हैं (मैंने इस तकनीक का उपयोग करके कोई अन्य उत्तर नहीं देखा है)।

public static <T> List<Pair<T, T>> consecutive(List<T> list) {
    List<Pair<T, T>> pairs = new LinkedList<>();
    list.stream().reduce((a, b) -> {
        pairs.add(new Pair<>(a, b));
        return b;
    });
    return pairs;
}

1
यह (1,2) (3,4) के बजाय (1,2) (2,3) वापस आएगा। इसके अलावा, मुझे यकीन नहीं है कि यह क्रम में लागू किया जाएगा (निश्चित रूप से इसकी कोई गारंटी नहीं है)।
अलेक्सांद्र डबिन्सकी

1
कृपया प्रश्न की जाँच करें, जो कि इच्छित व्यवहार है @ अलेक्ज़ेंडर डबिन्स्की
सैमटेबस

4
आह, हाँ, क्षमा करें। और सोचने के लिए, मैंने इसे लिखा।
डबिन्स्की


6

आप इसे स्लाइडिंग ऑपरेटर का उपयोग करके साइक्लोप्स-रिएक्शन (इस लाइब्रेरी में योगदान) में कर सकते हैं।

  LazyFutureStream.of( 0, 1, 2, 3, 4 )
                  .sliding(2)
                  .map(Pair::new);

या

   ReactiveSeq.of( 0, 1, 2, 3, 4 )
                  .sliding(2)
                  .map(Pair::new);

पेयर कंस्ट्रक्टर मानकर 2 तत्वों के साथ एक संग्रह स्वीकार कर सकता है।

यदि आप 4 से समूह बनाना चाहते हैं, और 2 से वेतन वृद्धि भी समर्थित है।

     ReactiveSeq.rangeLong( 0L,Long.MAX_VALUE)
                .sliding(4,2)
                .forEach(System.out::println);

Java.util.stream पर एक स्लाइडिंग दृश्य बनाने के लिए समतुल्य स्थैतिक विधियाँ। साइक्लॉप्स-स्ट्रीम स्ट्रीमयूटिल्स क्लास में भी प्रदान की जाती हैं ।

       StreamUtils.sliding(Stream.of(1,2,3,4),2)
                  .map(Pair::new);

नोट: - सिंगल-थ्रेडेड ऑपरेशन के लिए ReactiveSeq अधिक उपयुक्त होगा। LazyFutureStream ReactiveSeq का विस्तार करता है, लेकिन मुख्य रूप से समवर्ती / समानांतर उपयोग के लिए तैयार है (यह फ्यूचर्स की एक स्ट्रीम है)।

LazyFutureStream ReactiveSeq का विस्तार करता है जो Seq को भयानक jOOλ (जो java.util.stream.Stream को विस्तारित करता है) तक बढ़ाता है, इसलिए Lukas के प्रस्तुत समाधान भी स्ट्रीम प्रकार के साथ काम करेंगे। खिड़की / स्लाइडिंग ऑपरेटरों के बीच प्राथमिक मतभेदों में रुचि रखने वाले किसी के लिए भी अनंत धाराओं के साथ उपयोग के लिए स्पष्ट सापेक्ष शक्ति / जटिलता व्यापार बंद और उपयुक्तता है (स्लाइडिंग धारा का उपभोग नहीं करती है, लेकिन बफ़र्स जैसा कि यह बहता है)।


इस तरह से आप [(0,1) (2,3) ...] पर सवाल पूछते हैं [(0,1) (1,2) ...]। कृपया मेरा जवाब RxJava के साथ देखें ...
frhack

1
आप सही हैं, मेरा बुरा है, मैंने सवाल को गलत बताया - स्लाइडिंग ऑपरेटर यहां उपयोग करने के लिए सही है। मैं अपना जवाब अपडेट करूंगा - धन्यवाद!
जॉन मैकक्लेन

4

प्रोटॉन पैक पुस्तकालय विडों functionnality प्रदान करता है। एक जोड़ी वर्ग और एक स्ट्रीम को देखते हुए, आप इसे इस तरह से कर सकते हैं:

Stream<Integer> st = Stream.iterate(0 , x -> x + 1);
Stream<Pair<Integer, Integer>> pairs = StreamUtils.windowed(st, 2, 1)
                                                  .map(l -> new Pair<>(l.get(0), l.get(1)))
                                                  .moreStreamOps(...);

अब pairsधारा में शामिल हैं:

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, ...) and so on

हालाँकि, ऐसा लगता है कि आपको stदो बार बनाने की आवश्यकता है ! क्या यह लाइब्रेरी एकल स्ट्रीम का उपयोग करके समस्या को हल कर सकती है?
हांग्जो डबिन्स्की

@AleksandrDubinsky मुझे नहीं लगता कि यह वर्तमान स्प्लिटर्स के साथ उपलब्ध है। मैंने एक मुद्दा प्रस्तुत किया github.com/poetix/protonpack/issues/9
एलेक्सिस सी।

@AleksandrDubinsky windowedकार्यक्षमता को जोड़ दिया गया है! संपादन देखें।
एलेक्सिस सी।

1
आप अपने पुराने उत्तर को क्यों नहीं हटाते हैं, ताकि अन्य उपयोगकर्ता समाधान देख सकें, इतिहास नहीं।
अलेक्सांद्र डबिन्सकी

4

क्रमिक जोड़े ढूँढना

यदि आप किसी तीसरे पक्ष के पुस्तकालय का उपयोग करने के इच्छुक हैं और समानता की आवश्यकता नहीं है, तो jOOλ SQL- शैली विंडो फ़ंक्शन निम्नानुसार प्रदान करता है

System.out.println(
Seq.of(0, 1, 2, 3, 4)
   .window()
   .filter(w -> w.lead().isPresent())
   .map(w -> tuple(w.value(), w.lead().get())) // alternatively, use your new Pair() class
   .toList()
);

उपज

[(0, 1), (1, 2), (2, 3), (3, 4)]

lead()समारोह खिड़की से ट्रेवर्सल क्रम में अगले मूल्य तक पहुँचता है।

क्रमिक त्रिगुण / चौगुनी / एन-टुपल्स ढूँढना

टिप्पणियों में एक सवाल एक अधिक सामान्य समाधान के लिए पूछ रहा था, जहां जोड़े नहीं बल्कि एन-ट्यूपल्स (या संभवतः सूचियां) एकत्र की जानी चाहिए। इस प्रकार एक वैकल्पिक दृष्टिकोण है:

int n = 3;

System.out.println(
Seq.of(0, 1, 2, 3, 4)
   .window(0, n - 1)
   .filter(w -> w.count() == n)
   .map(w -> w.window().toList())
   .toList()
);

सूचियों की सूची तैयार करना

[[0, 1, 2], [1, 2, 3], [2, 3, 4]]

filter(w -> w.count() == n)परिणाम के बिना , परिणाम होगा

[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4], [4]]

अस्वीकरण: मैं jOOλ के पीछे कंपनी के लिए काम करता हूं


दिलचस्प। यदि मुझे समूह 3 या अधिक तत्वों की आवश्यकता है तो क्या होगा? का उपयोग करें w.lead().lead()?
राउल सैंटेलिंस 16

1
@RaulSantelices: tuple(w.value(), w.lead(1), w.lead(2))एक विकल्प होगा। मैंने अपना जवाब एक और सामान्य समाधान के साथ अपडेट किया हैlength = n
लुकास एडर

1
मैं सही ढंग से समझता हूं कि .window()आलसी ऑपरेशन नहीं है जो पूरे इनपुट स्ट्रीम को कुछ मध्यवर्ती संग्रह में इकट्ठा करता है, फिर उसमें से एक नई स्ट्रीम बनाता है?
टैगिर वलेव

@TagirValeev: हाँ, यह वर्तमान कार्यान्वयन है। उपरोक्त मामले में ( Comparatorविंडोज़ का पुन: उपयोग करने के लिए उपयोग नहीं किया जाता है), फिर इस तरह का अनुकूलन संभव होगा, और भविष्य में लागू होने की संभावना है।
लुकास एडर


2

हम RxJava (बहुत शक्तिशाली प्रतिक्रियाशील विस्तार पुस्तकालय) का उपयोग कर सकते हैं

IntStream intStream  = IntStream.iterate(1, n -> n + 1);

Observable<List<Integer>> pairObservable = Observable.from(intStream::iterator).buffer(2,1);

pairObservable.take(10).forEach(b -> {
            b.forEach(n -> System.out.println(n));
            System.out.println();
        });

बफर ऑपरेटर एक नमूदार कि एक नमूदार में उत्सर्जन करता है जो आइटम का उत्सर्जन करता है उन वस्तुओं का संग्रह बफ़र बदल देती है ..


1
मैंने Observable.zip(obs, obs.skip(1), pair->{...})अब तक का उपयोग किया ! मुझे नहीं पता Observable.bufferथा कि एक चरण के साथ एक संस्करण था (और मैं zipअजगर से चाल के लिए उपयोग किया जाता हूं )। +1
रीट शरबानी

1

आपरेशन तो वास्तव में नहीं क्या धाराओं को हल करने के लिए हैं अनिवार्य रूप से स्टेटफुल है - में "स्टेटलेस व्यवहार" खंड देखें जावाडोक :

सबसे अच्छा तरीका यह है कि संचालन को पूरी तरह से संचालित करने के लिए राज्य के व्यवहार संबंधी मापदंडों से बचें

एक समाधान यहां एक बाहरी काउंटर के माध्यम से अपनी स्ट्रीम में स्थिति का परिचय देना है, हालांकि यह केवल एक अनुक्रमिक स्ट्रीम के साथ काम करेगा।

public static void main(String[] args) {
    Stream<String> strings = Stream.of("a", "b", "c", "c");
    AtomicReference<String> previous = new AtomicReference<>();
    List<Pair> collect = strings.map(n -> {
                            String p = previous.getAndSet(n);
                            return p == null ? null : new Pair(p, n);
                        })
                        .filter(p -> p != null)
                        .collect(toList());
    System.out.println(collect);
}


static class Pair<T> {
    private T left, right;
    Pair(T left, T right) { this.left = left; this.right = right; }
    @Override public String toString() { return "{" + left + "," + right + '}'; }
}

प्रश्न इनपुट स्ट्रीम के क्रमिक तत्वों को इकट्ठा करने के लिए कहता है, न कि केवल क्रमिक पूर्णांक एकत्र करने के लिए। शब्दावली का एक महत्वपूर्ण स्पष्टीकरण Stream:! = "लंबदा"।
अलेक्सांद्र डबिन्सकी

आप एटोमिकइंटरफेरेंस द्वारा एटॉमिकइंटर को बदल सकते हैं। इसका विकल्प यह है कि आप अपने स्वयं के संग्राहक को रोल करें या बाहरी पुस्तकालयों का उपयोग करें जैसे कि इस उदाहरण में: stackoverflow.com/a/30090528/829571
assylias

मेरा संपादन देखें। इसके अलावा, मुझे यकीन नहीं है कि मैं लैम्बडा! = स्ट्रीम पर आपकी टिप्पणी को समझ सकता हूं। अनाम वर्ग का उपयोग करने वाले अन्य उत्तर अनिवार्य रूप से एक ही काम करते हैं, सिवाय इसके कि राज्य बाहरी होने के बजाय अनाम वर्ग द्वारा धारण किया जाता है ...
assylias

1
यह काम करता है। StreamExपुस्तकालय भी एक अच्छा खोज है और अपने आप में एक जवाब हो सकता है। "स्ट्रीम्स! = लैंबडास" पर मेरी टिप्पणी आपको यह बताते हुए कहती है "ऑपरेशन अनिवार्य रूप से स्टेटफुल है इसलिए वास्तव में लैंबडास हल करने के लिए नहीं है।" मुझे लगता है कि आप "धारा" शब्द का उपयोग करने के लिए थे।
हांग्जो डबिन्स्की

ओह, मैं देख रहा हूँ - मैंने स्पष्ट किया है।
assylias

0

आपके मामले में, मैं अपना कस्टम IntFunction लिखूंगा जो अंतिम इंट पास का ट्रैक रखता है और मूल IntStream को मैप करने के लिए उपयोग करता है।

import java.util.function.IntFunction;
import java.util.stream.IntStream;

public class PairFunction implements IntFunction<PairFunction.Pair> {

  public static class Pair {

    private final int first;
    private final int second;

    public Pair(int first, int second) {
      this.first = first;
      this.second = second;
    }

    @Override
    public String toString() {
      return "[" + first + "|" + second + "]";
    }
  }

  private int last;
  private boolean first = true;

  @Override
  public Pair apply(int value) {
    Pair pair = !first ? new Pair(last, value) : null;
    last = value;
    first = false;
    return pair;
  }

  public static void main(String[] args) {

    IntStream intStream = IntStream.of(0, 1, 2, 3, 4);
    final PairFunction pairFunction = new PairFunction();
    intStream.mapToObj(pairFunction)
        .filter(p -> p != null) // filter out the null
        .forEach(System.out::println); // display each Pair

  }

}

इसके साथ समस्या यह है कि यह खिड़की से बाहर बेकारता फेंकता है।
रोब

@ रब और क्या समस्या है?
अलेक्सांद्र डबिन्सकी

लैम्ब्डा के मुख्य बिंदुओं में से एक में उत्परिवर्तनीय स्थिति नहीं है, ताकि आंतरिक इंटीग्रेटर्स काम को समानांतर कर सकें।
रोब

@ रब: हाँ, आप सही हैं, लेकिन दिया गया उदाहरण स्ट्रीम समानता को वैसे भी परिभाषित करता है जैसे प्रत्येक आइटम (पहले और अंतिम वाले को छोड़कर) का उपयोग किसी जोड़ी के पहले और दूसरे आइटम के रूप में किया जाता है।
jpvee

@jpvee हाँ मुझे लगा कि आप क्या सोच रहे थे। मुझे आश्चर्य है कि अगर किसी अन्य मैपर के साथ ऐसा करने का कोई तरीका नहीं है। संक्षेप में, आप सभी की आवश्यकता होगी कि लूप इन्क्रीमेंटर को दो से घुमाया जाए तो फ़नकार को 2 तर्क देने होंगे। यह संभव होना चाहिए।
रोब

0

समय-श्रृंखला के समय (x- मान) में क्रमिक अंतरों की गणना के लिए, मैं stream's collect(...)विधि का उपयोग करता हूं :

final List< Long > intervals = timeSeries.data().stream()
                    .map( TimeSeries.Datum::x )
                    .collect( DifferenceCollector::new, DifferenceCollector::accept, DifferenceCollector::combine )
                    .intervals();

जहां कुछ इस प्रकार है:

public class DifferenceCollector implements LongConsumer
{
    private final List< Long > intervals = new ArrayList<>();
    private Long lastTime;

    @Override
    public void accept( final long time )
    {
        if( Objects.isNull( lastTime ) )
        {
            lastTime = time;
        }
        else
        {
            intervals.add( time - lastTime );
            lastTime = time;
        }
    }

    public void combine( final DifferenceCollector other )
    {
        intervals.addAll( other.intervals );
        lastTime = other.lastTime;
    }

    public List< Long > intervals()
    {
        return intervals;
    }
}

आप शायद अपनी आवश्यकताओं के अनुरूप इसे संशोधित कर सकते हैं।


0

मैंने आखिरकार स्ट्रीम करने का एक तरीका निकाला है। मानों के जोड़े के साथ बड़े करीने से निपटने में सक्षम होने के लिए स्ट्रीम करें। ऐसे उपयोग मामलों की एक भीड़ है जिन्हें इस सुविधा की आवश्यकता होती है जो JDK 8 में स्वाभाविक रूप से प्रकट नहीं होती है :

public static int ArithGeo(int[] arr) {
    //Geometric
    List<Integer> diffList = new ArrayList<>();
    List<Integer> divList = new ArrayList<>();
    Arrays.stream(arr).reduce((left, right) -> {
        diffList.add(right-left);
        divList.add(right/left);
        return right;
    });
    //Arithmetic
    if(diffList.stream().distinct().count() == 1) {
        return 1;
    }
    //Geometric
    if(divList.stream().distinct().count() == 1) {
        return 2;
    }
    return -1;
}

चाल मैं उपयोग वापसी सही है; बयान।


1
मुझे नहीं लगता कि reduceइसके लिए काम करने के लिए पर्याप्त गारंटी है।
Aleksandr Dubinsky

पर्याप्त गारंटी के बारे में अधिक जानने के लिए दिलचस्पी होगी । क्या आप कृपया विस्तार से बता सकते हैं? शायद अमरूद में एक विकल्प है ... लेकिन मैं विवश हूँ और इसका उपयोग नहीं कर सकता।
बीजर

-1

ज़िप का उपयोग करने के लिए एक सुंदर समाधान होगा । कुछ इस तरह:

List<Integer> input = Arrays.asList(0, 1, 2, 3, 4);
Stream<Pair> pairStream = Streams.zip(input.stream(),
                                      input.stream().substream(1),
                                      (a, b) -> new Pair(a, b)
);

यह बहुत संक्षिप्त और सुरुचिपूर्ण है, हालांकि यह एक इनपुट के रूप में एक सूची का उपयोग करता है। एक अनंत धारा स्रोत को इस तरह संसाधित नहीं किया जा सकता है।

एक और (बहुत अधिक परेशानी वाला) मुद्दा यह है कि पूरे स्ट्रीम क्लास के साथ ज़िप को एपीआई से हाल ही में हटा दिया गया है। उपरोक्त कोड केवल b95 या पुराने रिलीज के साथ काम करता है । तो नवीनतम JDK के साथ मैं कहूंगा कि कोई भी FP शैली का समाधान नहीं है और अभी हम केवल यह आशा कर सकते हैं कि किसी तरह zip को एपीआई में फिर से प्रस्तुत किया जाएगा।


वास्तव में, zipहटा दिया गया था। मुझे याद नहीं है कि Streamsकक्षा में क्या था , लेकिन कुछ चीजें Streamइंटरफ़ेस पर स्थिर तरीके से माइग्रेट हो गई हैं , StreamSupportऔर Stream.Builderकक्षाएं भी हैं।
स्टुअर्ट मार्क्स

ये सही है। कुछ अन्य तरीके जैसे कि कॉनैट या इटरेट स्थानांतरित हो गए हैं और स्ट्रीम में डिफ़ॉल्ट तरीके बन गए हैं। दुख की बात है कि ज़िप को एपीआई से हटा दिया गया था। मैं इस पसंद के पीछे के कारणों को समझता हूं (जैसे टुपल्स की कमी) लेकिन फिर भी यह एक अच्छी विशेषता थी।
गैजेट

2
@ गुड़ टुपल्स का क्या करना है zip? जो भी पांडित्यपूर्ण कारण का आविष्कार किया जा सकता है वह हत्या को सही नहीं ठहराता है zip
Aleksandr Dubinsky

@AleksandrDubinsky ज्यादातर मामलों में ज़िप का उपयोग आउटपुट के रूप में जोड़े / टुपल्स के संग्रह का उत्पादन करने के लिए किया जाता है। उनका तर्क था कि अगर वे जिप रखते थे तो लोग टीडीपी के साथ-साथ जेडीके के हिस्से के रूप में मांगेंगे। मैं एक मौजूदा सुविधा हालांकि कभी नहीं हटा दिया होता।
गैजेट

-1

यह एक दिलचस्प समस्या है। क्या मेरा हाइब्रिड प्रयास किसी भी अच्छे से नीचे है?

public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1, 2, 3);
    Iterator<Integer> first = list.iterator();
    first.next();
    if (first.hasNext())
        list.stream()
        .skip(1)
        .map(v -> new Pair(first.next(), v))
        .forEach(System.out::println);
}

मेरा मानना ​​है कि यह खुद को समानांतर प्रसंस्करण के लिए उधार नहीं देता है, और इसलिए अयोग्य ठहराया जा सकता है।


सवाल समानांतर प्रसंस्करण के लिए नहीं पूछा गया था, लेकिन यह मान लिया कि हमारे पास केवल एक है Stream, एक नहीं List। बेशक, हम एक स्ट्रीम से एक पुनरावृत्त के रूप में अच्छी तरह से pry कर सकते हैं, इसलिए यह एक वैध समाधान हो सकता है। फिर भी, यह एक मूल दृष्टिकोण है।
Aleksandr Dubinsky

-1

जैसा कि दूसरों ने देखा है, समस्या की प्रकृति के कारण, कुछ राज्य की आवश्यकता है।

मुझे एक ऐसी ही समस्या का सामना करना पड़ा, जिसमें मैं चाहता था कि ओरेकल एसक्यूएल फ़ंक्शन LEAD अनिवार्य रूप से था। इसे लागू करने का मेरा प्रयास नीचे है।

/**
 * Stream that pairs each element in the stream with the next subsequent element.
 * The final pair will have only the first item, the second will be null.
 */
<T> Spliterator<Pair<T>> lead(final Stream<T> stream)
{
    final Iterator<T> input = stream.sequential().iterator();

    final Iterable<Pair<T>> iterable = () ->
    {
        return new Iterator<Pair<T>>()
        {
            Optional<T> current = getOptionalNext(input);

            @Override
            public boolean hasNext()
            {
                return current.isPresent();
            }

            @Override
            public Pair<T> next()
            {
                Optional<T> next = getOptionalNext(input);
                final Pair<T> pair = next.isPresent()
                    ? new Pair(current.get(), next.get())
                    : new Pair(current.get(), null);
                current = next;

                return pair;
            }
        };
    };

    return iterable.spliterator();
}

private <T> Optional<T> getOptionalNext(final Iterator<T> iterator)
{
    return iterator.hasNext()
        ? Optional.of(iterator.next())
        : Optional.empty();
}

-1

आप स्ट्रीम के माध्यम से बहने वाले तत्वों को संग्रहीत करने के लिए एक बंधी हुई कतार का उपयोग करके प्राप्त कर सकते हैं (जो इस विचार पर आधारित है, जिसका मैंने यहां विस्तार से वर्णन किया है: क्या स्ट्रीम में अगला तत्व प्राप्त करना संभव है? )

Belows का उदाहरण पहले बाउंडेडक्यू वर्ग की आवृत्ति को परिभाषित करता है जो स्ट्रीम के माध्यम से जाने वाले तत्वों को संग्रहीत करेगा (यदि आपको लिंक्डलिस्ट का विस्तार करने का विचार पसंद नहीं है, तो वैकल्पिक और अधिक सामान्य दृष्टिकोण के लिए ऊपर दिए गए लिंक को देखें)। बाद में आप केवल दो बाद के तत्वों को जोड़ी में जोड़ते हैं:

public class TwoSubsequentElems {
  public static void main(String[] args) {
    List<Integer> input = new ArrayList<Integer>(asList(0, 1, 2, 3, 4));

    class BoundedQueue<T> extends LinkedList<T> {
      public BoundedQueue<T> save(T curElem) {
        if (size() == 2) { // we need to know only two subsequent elements
          pollLast(); // remove last to keep only requested number of elements
        }

        offerFirst(curElem);

        return this;
      }

      public T getPrevious() {
        return (size() < 2) ? null : getLast();
      }

      public T getCurrent() {
        return (size() == 0) ? null : getFirst();
      }
    }

    BoundedQueue<Integer> streamHistory = new BoundedQueue<Integer>();

    final List<Pair<Integer>> answer = input.stream()
      .map(i -> streamHistory.save(i))
      .filter(e -> e.getPrevious() != null)
      .map(e -> new Pair<Integer>(e.getPrevious(), e.getCurrent()))
      .collect(Collectors.toList());

    answer.forEach(System.out::println);
  }
}

-3

मैं @aepurniet से सहमत हूं लेकिन इसके बजाय आपको मैप का उपयोग करना होगा

range(0, 100).mapToObj((i) -> new Pair(i, i+1)).forEach(System.out::println);

1
सही। लेकिन यह केवल पूर्णांकों के जोड़े को इकट्ठा करता है, न कि किसी धारा के तत्वों के जोड़े (किसी भी प्रकार का)।
हांग्जो डबिन्सकी

-5

एक forलूप चलाएं जो length-1आपकी स्ट्रीम में 0 से चलता है

for(int i = 0 ; i < stream.length-1 ; i++)
{
    Pair pair = new Pair(stream[i], stream[i+1]);
    // then add your pair to an array
}

3
और समाधान का लंबोदर हिस्सा कहाँ है?
ओलपिम्पू पीओपी

जब धारा अनंत हो तो ऐसा नहीं है
mishadoff

@ ऑलिम्पियु - आपको एक मेमना कहाँ से मिला? मैंने यह सुनिश्चित करने के लिए दो बार प्रश्न पढ़ा कि मैं इसे याद नहीं कर रहा था। मैंने संपादन का इतिहास भी जांचा। और प्रश्न को इसके साथ टैग नहीं किया गया है।
jww
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.