जावा 8 स्ट्रीम रिवर्स ऑर्डर


153

सामान्य प्रश्न: किसी धारा को उलटने का उचित तरीका क्या है? यह मानते हुए कि हमें पता नहीं है कि किस प्रकार के तत्व हैं, जिसमें किसी भी स्ट्रीम को रिवर्स करने का सामान्य तरीका क्या है?

विशिष्ट प्रश्न:

IntStreamइंटेगर को विशिष्ट रेंज में उत्पन्न करने के लिए रेंज विधि प्रदान करता है IntStream.range(-range, 0), अब जब मैं इसे 0 से नकारात्मक रेंज में बदलना चाहता हूं तो यह नकारात्मक नहीं चलेगा, मैं भी इसका उपयोग नहीं कर सकताInteger::compare

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);

साथ IntStreamमैं इस संकलक त्रुटि मिलेगी

त्रुटि: (191, 0) ajc: sorted()प्रकार पद्धति IntStreamतर्क के लिए लागू नहीं है ( Integer::compare)

मुझे यहां क्या समझ नहीं आ रहा है?


1
एक विधि IntStreamनहीं .sorted(Comparator)है; आपको Stream<Integer>पहली बार वहां से IntStream
गुजरना होगा

ठीक है, मैंने इसे पाया है, आपको .boxed () और फिर .sorted () का उपयोग करने की आवश्यकता है
vach

4
IntStream.range(0, n)रिवर्स ऑर्डर उत्पन्न करने के लिए , कुछ ऐसा करें map(i -> n - i - 1)। मुक्केबाजी और छंटाई करने की आवश्यकता नहीं है।
स्टुअर्ट मार्क्स

1
आपका सरस प्रश्न और आपके विशिष्ट प्रश्न मेरे लिए दो पूर्ण भिन्न प्रश्नों की तरह पढ़ें। सामान्य धारा को उलटने की बात करता है, जबकि विशिष्ट क्रम में अवरोही क्रम में संख्याओं की बात करता है। यदि धारा अनियंत्रित तरीके से संख्याओं का उत्पादन करती है 1, 3, 2, तो आपका अपेक्षित परिणाम क्या है? क्या आप उलटी धारा चाहते हैं जैसे 2, 3, 1या छांटी गई धारा 3, 2, 1?
चिकोडोरो

8
आप सामान्य रूप से एक धारा को उलट नहीं सकते हैं - उदाहरण के लिए एक धारा अप्रभावी हो सकती है।
9

जवाबों:


78

रिवर्स उत्पन्न करने के विशिष्ट प्रश्न के लिए IntStream, कुछ इस तरह से प्रयास करें:

static IntStream revRange(int from, int to) {
    return IntStream.range(from, to)
                    .map(i -> to - i + from - 1);
}

यह बॉक्सिंग और सॉर्टिंग से बचा जाता है।

किसी भी प्रकार की धारा को उल्टा करने के सामान्य प्रश्न के लिए, मुझे "उचित" तरीके का पता नहीं है। कुछ तरीके हैं जिनसे मैं सोच सकता हूं। दोनों अंत तत्वों को संग्रहीत करते हैं। मुझे तत्वों को संग्रहीत किए बिना एक धारा को उल्टा करने का तरीका नहीं पता है।

यह पहला तरीका तत्वों को एक सरणी में संग्रहीत करता है और उन्हें रिवर्स ऑर्डर में एक स्ट्रीम में पढ़ता है। ध्यान दें कि चूंकि हम स्ट्रीम तत्वों के रनटाइम प्रकार को नहीं जानते हैं, इसलिए हम अनियंत्रित कलाकारों की आवश्यकता होने पर सरणी को ठीक से टाइप नहीं कर सकते हैं।

@SuppressWarnings("unchecked")
static <T> Stream<T> reverse(Stream<T> input) {
    Object[] temp = input.toArray();
    return (Stream<T>) IntStream.range(0, temp.length)
                                .mapToObj(i -> temp[temp.length - i - 1]);
}

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

Stream<T> input = ... ;
List<T> output =
    input.collect(ArrayList::new,
                  (list, e) -> list.add(0, e),
                  (list1, list2) -> list1.addAll(0, list2));

यह संभव है कि किसी प्रकार के अनुकूलित डेटा संरचना का उपयोग करके अधिक कुशल रिवर्सल कलेक्टर लिखना संभव हो।

अद्यतन 2016-01-29

चूँकि इस सवाल पर हाल ही में थोड़ा ध्यान दिया गया है, मुझे लगता है कि मुझे अपने जवाब को अद्यतन करना चाहिए ताकि सामने वाले को समस्या का समाधान करना पड़े ArrayList । यह ओ (एन ^ 2) प्रतिलिपि की आवश्यकता वाले तत्वों की एक बड़ी संख्या के साथ बहुत ही अयोग्य होगा।

इसके ArrayDequeबजाय उपयोग करना बेहतर होता है , जो सामने की ओर सम्मिलन का कुशलता से समर्थन करता है। एक छोटी सी शिकन यह है कि हम तीन-arg फॉर्म का उपयोग नहीं कर सकते हैं Stream.collect(); इसके लिए आवश्यक है कि दूसरे arg की सामग्री को पहले arg में मिला दिया जाए, और इसमें कोई "add-all-at-front" बल्क नहीं है Deque। इसके बजाय, हम addAll()पहले आर्ग की सामग्री को दूसरे के अंत तक जोड़ने के लिए उपयोग करते हैं, और फिर हम दूसरे को वापस करते हैं। इसके उपयोग की आवश्यकता हैCollector.of() फ़ैक्टरी विधि पड़ता है।

पूरा कोड यह है:

Deque<String> output =
    input.collect(Collector.of(
        ArrayDeque::new,
        (deq, t) -> deq.addFirst(t),
        (d1, d2) -> { d2.addAll(d1); return d2; }));

परिणाम एक के Dequeबजाय एक है List, लेकिन यह एक मुद्दे का ज्यादा नहीं होना चाहिए, क्योंकि यह आसानी से पुनरावृत्त या अब-उल्टे क्रम में प्रवाहित हो सकता है।


15
वैकल्पिक रूप से:IntStream.iterate(to-1, i->i-1).limit(to-from)
होल्गर

2
@ हेलर दुर्भाग्य से, वह समाधान अतिप्रवाह को सही ढंग से नहीं संभालता है
ब्रैंडन

2
@ ब्रैंडन माइनर: वास्तव में, आपको .limit(endExcl-(long)startIncl)इसके बजाय उपयोग करना होगा , लेकिन ऐसी बड़ी धाराओं के लिए, यह वैसे भी बहुत हतोत्साहित करता है क्योंकि यह rangeआधारित समाधान की तुलना में बहुत कम कुशल है । जिस समय मैंने टिप्पणी लिखी थी, मैं दक्षता अंतर के बारे में नहीं जानता था।
होल्गर

48

सुरुचिपूर्ण समाधान

List<Integer> list = Arrays.asList(1,2,3,4);
list.stream()
    .boxed() // Converts Intstream to Stream<Integer>
    .sorted(Collections.reverseOrder()) // Method on Stream<Integer>
    .forEach(System.out::println);

6
यह सुरुचिपूर्ण है लेकिन पूरी तरह से काम नहीं कर रहा है क्योंकि ऐसा लगता है कि सूची के तत्वों को होना आवश्यक है Comparable...
क्रिज़िस्तोफ़ वोल्टी

26
यह मानते हुए कि हम चाहते हैं कि तत्वों को उल्टे क्रम में क्रमबद्ध किया जाए। सवाल एक धारा के आदेश को उलटने के बारे में है।
डिलन रयान रेडिंग

37

यहाँ कई समाधान सॉर्ट या रिवर्स होते हैं IntStream, लेकिन अनावश्यक रूप से मध्यवर्ती भंडारण की आवश्यकता होती है। स्टुअर्ट मार्क्स के समाधान के लिए रास्ता है:

static IntStream revRange(int from, int to) {
    return IntStream.range(from, to).map(i -> to - i + from - 1);
}

यह सही ढंग से अतिप्रवाह को भी संभालता है, इस परीक्षा को पास करते हुए:

@Test
public void testRevRange() {
    assertArrayEquals(revRange(0, 5).toArray(), new int[]{4, 3, 2, 1, 0});
    assertArrayEquals(revRange(-5, 0).toArray(), new int[]{-1, -2, -3, -4, -5});
    assertArrayEquals(revRange(1, 4).toArray(), new int[]{3, 2, 1});
    assertArrayEquals(revRange(0, 0).toArray(), new int[0]);
    assertArrayEquals(revRange(0, -1).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MAX_VALUE, MAX_VALUE).toArray(), new int[0]);
    assertArrayEquals(revRange(MIN_VALUE, MIN_VALUE + 1).toArray(), new int[]{MIN_VALUE});
    assertArrayEquals(revRange(MAX_VALUE - 1, MAX_VALUE).toArray(), new int[]{MAX_VALUE - 1});
}

भयानक और सरल। क्या यह कुछ ओपनसोर्स उपयोगिता से है? (अनुमान की बात) या आपके कोड का कोई टुकड़ा?
vach

धन्यवाद! दुर्भाग्य से, मेरा Estreamsनाम लीक करने का इरादा नहीं था (मैं इसे पोस्ट से हटाने जा रहा हूं)। यह हमारी कंपनी की आंतरिक उपयोगिता वर्गों में से एक है, जिसका उपयोग हम पूरक java.util.stream.Streamके staticतरीकों के लिए करते हैं।
ब्रैंडन

3
ठीक है ... "भयानक और सरल" ... क्या कोई भी मामला है जो इस समाधान को संभालता है, जो स्टुअर्ट मार्क्स के भी सरल समाधान पहले से ही डेढ़ साल से अधिक नहीं संभाल रहा है?
Holger

मैंने अभी ऊपर परीक्षण विधि के साथ उसके समाधान का परीक्षण किया; वो चला गया। मैं अनावश्यक रूप से उसे गले लगाने के बजाय अतिप्रवाह से बच रहा था जैसा उसने किया था। मैं इस बात से सहमत हूं कि उनकी स्थिति बेहतर है। मैं उसे संपादित करने के लिए विचार करूंगा।
ब्रैंडन

1
@vach, आप StreamExस्टेप निर्दिष्ट करके उपयोग कर सकते हैं :IntStreamEx.rangeClosed(from-1, to, -1)
Tagir Valeev

34

सामान्य प्रश्न:

स्ट्रीम किसी भी तत्व को संग्रहीत नहीं करता है।

तो कुछ मध्यवर्ती संग्रह में तत्वों को संग्रहीत किए बिना रिवर्स ऑर्डर में तत्वों की पुनरावृत्ति संभव नहीं है।

Stream.of("1", "2", "20", "3")
      .collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList
      .descendingIterator()
      .forEachRemaining(System.out::println);

अपडेट: ArrayDeque (बेहतर) के लिए लिंक किए गए लिंक्डलिस्ट विवरण के लिए यहां देखें

प्रिंटों:

3

20

2

1

वैसे, sortविधि का उपयोग करना सही नहीं है क्योंकि यह छंटनी नहीं करता है, (उल्टे धारा में असमान तत्व हो सकते हैं)

विशिष्ट प्रश्न:

मुझे यह सरल, आसान और सहज लगा (Copied @Holger टिप्पणी )

IntStream.iterate(to - 1, i -> i - 1).limit(to - from)

3
कुछ स्ट्रीम ऑपरेशन, जैसे कि sortedऔर distinctवास्तव में एक मध्यवर्ती परिणाम संग्रहीत करते हैं। उस बारे में कुछ जानकारी के लिए पैकेज एपीआई डॉक्स देखें ।
Lii

@Lii मैं No storageएक ही पृष्ठ में देखता हूं । यहां तक ​​कि यह स्टोर करता है कि हम उस स्टोरेज तक पहुंच नहीं सकते (इसलिए No storageमुझे लगता है कि ठीक है)
वेंकट राजू

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

मैं एक समझने योग्य परिप्रेक्ष्य से समाधान की सादगी पसंद करता हूं और मौजूदा डेटा संरचना पर एक मौजूदा विधि का लाभ उठाता हूं ... एक मानचित्र कार्यान्वयन के साथ पिछले समाधान को समझना मुश्किल है, लेकिन यह सुनिश्चित करने के लिए कि मनु सही है, बड़े संग्रह के लिए मैं इसका उपयोग नहीं करूंगा सहज ज्ञान युक्त, और ऊपर दिए गए नक्शे का विकल्प चुन सकते हैं।
बीजर

यह यहाँ कुछ सही उत्तरों में से एक है। अन्य लोगों में से अधिकांश वास्तव में धारा को उल्टा नहीं करते हैं, वे इसे किसी भी तरह से करने से बचने की कोशिश करते हैं (जो केवल परिस्थितियों के अजीब सेट के तहत काम करता है जिसके तहत आपको आमतौर पर पहली जगह में उलटने की आवश्यकता नहीं होगी)। यदि आप एक धारा को उलटने की कोशिश करते हैं जो स्मृति में फिट नहीं होती है तो आप इसे गलत कर रहे हैं। इसे एक DB में डंप करें और नियमित SQL का उपयोग करके एक उलट धारा प्राप्त करें।
घन

19

बिना बाहरी काम के ...

import java.util.List;
import java.util.Collections;
import java.util.stream.Collector;

public class MyCollectors {

    public static <T> Collector<T, ?, List<T>> toListReversed() {
        return Collectors.collectingAndThen(Collectors.toList(), l -> {
            Collections.reverse(l);
            return l;
        });
    }

}

15

यदि लागू किया Comparable<T>(उदा। Integer, String, Date), आप इसे उपयोग कर सकते हैं Comparator.reverseOrder()

List<Integer> list = Arrays.asList(1, 2, 3, 4);
list.stream()
     .sorted(Comparator.reverseOrder())
     .forEach(System.out::println);

6
यह धारा को उलट नहीं करता है। यह धारा को उल्टे क्रम में काटता है। तो अगर आप Stream.of(1,3,2)परिणाम Stream.of(3,2,1)नहीं होगाStream.of(2,3,1)
wilmol

12

आप अपने स्वयं के कलेक्टर को परिभाषित कर सकते हैं जो तत्वों को रिवर्स ऑर्डर में इकट्ठा करता है:

public static <T> Collector<T, List<T>, List<T>> inReverse() {
    return Collector.of(
        ArrayList::new,
        (l, t) -> l.add(t),
        (l, r) -> {l.addAll(r); return l;},
        Lists::<T>reverse);
}

और इसका उपयोग करें:

stream.collect(inReverse()).forEach(t -> ...)

मैं कुशलता से आइटम (सूची के अंत में) इकट्ठा करने के लिए आगे के क्रम में एक ArrayList का उपयोग करता हूं, और अमरूद Lists.reverse कुशलता से सूची की एक दूसरी प्रति बनाने के बिना सूची का एक उल्टा दृश्य देने के लिए।

यहाँ कस्टम कलेक्टर के लिए कुछ परीक्षण मामले हैं:

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

import org.hamcrest.Matchers;
import org.junit.Test;

import com.google.common.collect.Lists;

public class TestReverseCollector {
    private final Object t1 = new Object();
    private final Object t2 = new Object();
    private final Object t3 = new Object();
    private final Object t4 = new Object();

    private final Collector<Object, List<Object>, List<Object>> inReverse = inReverse();
    private final Supplier<List<Object>> supplier = inReverse.supplier();
    private final BiConsumer<List<Object>, Object> accumulator = inReverse.accumulator();
    private final Function<List<Object>, List<Object>> finisher = inReverse.finisher();
    private final BinaryOperator<List<Object>> combiner = inReverse.combiner();

    @Test public void associative() {
        final List<Object> a1 = supplier.get();
        accumulator.accept(a1, t1);
        accumulator.accept(a1, t2);
        final List<Object> r1 = finisher.apply(a1);

        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        final List<Object> a3 = supplier.get();
        accumulator.accept(a3, t2);
        final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));

        assertThat(r1, Matchers.equalTo(r2));
    }

    @Test public void identity() {
        final List<Object> a1 = supplier.get();
        accumulator.accept(a1, t1);
        accumulator.accept(a1, t2);
        final List<Object> r1 = finisher.apply(a1);

        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        accumulator.accept(a2, t2);
        final List<Object> r2 = finisher.apply(combiner.apply(a2, supplier.get()));

        assertThat(r1, equalTo(r2));
    }

    @Test public void reversing() throws Exception {
        final List<Object> a2 = supplier.get();
        accumulator.accept(a2, t1);
        accumulator.accept(a2, t2);

        final List<Object> a3 = supplier.get();
        accumulator.accept(a3, t3);
        accumulator.accept(a3, t4);

        final List<Object> r2 = finisher.apply(combiner.apply(a2, a3));

        assertThat(r2, contains(t4, t3, t2, t1));
    }

    public static <T> Collector<T, List<T>, List<T>> inReverse() {
        return Collector.of(
            ArrayList::new,
            (l, t) -> l.add(t),
            (l, r) -> {l.addAll(r); return l;},
            Lists::<T>reverse);
    }
}

9

साइक्लोप प्रतिक्रिया StreamUtils एक रिवर्स स्ट्रीम विधि (है जावाडोक )।

  StreamUtils.reverse(Stream.of("1", "2", "20", "3"))
             .forEach(System.out::println);

यह एक ArrayList को इकट्ठा करके और फिर ListIterator वर्ग का उपयोग करके काम करता है जो सूची में पीछे की ओर जाने के लिए या तो दिशा में पुनरावृति कर सकता है।

यदि आपके पास पहले से सूची है, तो यह अधिक कुशल होगा

  StreamUtils.reversedStream(Arrays.asList("1", "2", "20", "3"))
             .forEach(System.out::println);

1
इस परियोजना के बारे में अच्छा पता नहीं था
vach

1
साइक्लॉप अब कुशल स्ट्रीम रिवर्सल (वर्तमान में रेंज, सरणियों और सूचियों के लिए) के लिए Spliterators के साथ भी आता है । CquenceM.of, SequenceM.range या SequenceM.fromList के साथ साइक्लॉप्स SequenceM स्ट्रीम एक्सटेंशन बनाना स्वचालित रूप से कुशलतापूर्वक प्रतिवर्ती spliterators का लाभ उठाएगा।
जॉन मैक्लेन

6

मैं सुझाव देता हूं कि jOOλ का उपयोग करते हुए , यह एक महान पुस्तकालय है जो जावा 8 स्ट्रीम और लैम्ब्डा में बहुत उपयोगी कार्यक्षमता जोड़ता है।

फिर आप निम्न कार्य कर सकते हैं:

List<Integer> list = Arrays.asList(1,2,3,4);    
Seq.seq(list).reverse().forEach(System.out::println)

इतना ही आसान। यह एक बहुत हल्का पुस्तकालय है, और किसी भी जावा 8 परियोजना में जोड़ने लायक है।


5

यहाँ मैं के साथ आया है समाधान है:

private static final Comparator<Integer> BY_ASCENDING_ORDER = Integer::compare;
private static final Comparator<Integer> BY_DESCENDING_ORDER = BY_ASCENDING_ORDER.reversed();

फिर उन तुलनित्रों का उपयोग करना:

IntStream.range(-range, 0).boxed().sorted(BY_DESCENDING_ORDER).forEach(// etc...

2
यह केवल आपके "विशिष्ट प्रश्न" का उत्तर है, लेकिन आपके "सामान्य प्रश्न" का नहीं।
चिक्कोडोरो

9
Collections.reverseOrder()जावा 1.2 के बाद से मौजूद है और साथ काम करता है Integer...
Holger

4

इस उपयोगिता विधि के बारे में कैसे?

public static <T> Stream<T> getReverseStream(List<T> list) {
    final ListIterator<T> listIt = list.listIterator(list.size());
    final Iterator<T> reverseIterator = new Iterator<T>() {
        @Override
        public boolean hasNext() {
            return listIt.hasPrevious();
        }

        @Override
        public T next() {
            return listIt.previous();
        }
    };
    return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
            reverseIterator,
            Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
}

नकल के बिना सभी मामलों के साथ काम करने लगता है।


मुझे यह समाधान बहुत पसंद है। अधिकांश उत्तर दो श्रेणियों में विभाजित होते हैं: (1) संग्रह को उल्टा करें और (।) इसे, (2) कस्टम कलेक्टरों से अपील करें। दोनों बिल्कुल अनावश्यक हैं। अन्यथा, यह JDK 8 में ही कुछ गंभीर भाषा अभिव्यक्ति के मुद्दे के बारे में गवाही दे सकता है। और आपका उत्तर विपरीत साबित होता है :)
vitrums

4
List newStream = list.stream().sorted(Collections.reverseOrder()).collect(Collectors.toList());
        newStream.forEach(System.out::println);

3

सबसे सरल तरीका (सरल संग्रह - समानांतर धाराओं का समर्थन करता है):

public static <T> Stream<T> reverse(Stream<T> stream) {
    return stream
            .collect(Collector.of(
                    () -> new ArrayDeque<T>(),
                    ArrayDeque::addFirst,
                    (q1, q2) -> { q2.addAll(q1); return q2; })
            )
            .stream();
}

उन्नत तरीका (निरंतर तरीके से समानांतर धाराओं का समर्थन करता है):

public static <T> Stream<T> reverse(Stream<T> stream) {
    Objects.requireNonNull(stream, "stream");

    class ReverseSpliterator implements Spliterator<T> {
        private Spliterator<T> spliterator;
        private final Deque<T> deque = new ArrayDeque<>();

        private ReverseSpliterator(Spliterator<T> spliterator) {
            this.spliterator = spliterator;
        }

        @Override
        @SuppressWarnings({"StatementWithEmptyBody"})
        public boolean tryAdvance(Consumer<? super T> action) {
            while(spliterator.tryAdvance(deque::addFirst));
            if(!deque.isEmpty()) {
                action.accept(deque.remove());
                return true;
            }
            return false;
        }

        @Override
        public Spliterator<T> trySplit() {
            // After traveling started the spliterator don't contain elements!
            Spliterator<T> prev = spliterator.trySplit();
            if(prev == null) {
                return null;
            }

            Spliterator<T> me = spliterator;
            spliterator = prev;
            return new ReverseSpliterator(me);
        }

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

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

        @Override
        public Comparator<? super T> getComparator() {
            Comparator<? super T> comparator = spliterator.getComparator();
            return (comparator != null) ? comparator.reversed() : null;
        }

        @Override
        public void forEachRemaining(Consumer<? super T> action) {
            // Ensure that tryAdvance is called at least once
            if(!deque.isEmpty() || tryAdvance(action)) {
                deque.forEach(action);
            }
        }
    }

    return StreamSupport.stream(new ReverseSpliterator(stream.spliterator()), stream.isParallel());
}

ध्यान दें कि आप जल्दी से अन्य प्रकार की धाराओं (IntStream, ...) तक फैल सकते हैं।

परिक्षण:

// Use parallel if you wish only
revert(Stream.of("One", "Two", "Three", "Four", "Five", "Six").parallel())
    .forEachOrdered(System.out::println);

परिणाम:

Six
Five
Four
Three
Two
One

अतिरिक्त नोट्स:simplest way यह इतना उपयोगी है जब अन्य धारा के संचालन के साथ उपयोग नहीं है (कलेक्ट टूटता समानांतरवाद में शामिल होने)। यह advance wayमुद्दा नहीं है, और यह धारा की प्रारंभिक विशेषताओं को भी रखता है, उदाहरण के लिए SORTED, और इसलिए, यह रिवर्स के बाद अन्य स्ट्रीम ऑपरेशन के साथ उपयोग करने का तरीका है।


2

कोई ऐसा कलेक्टर लिख सकता है जो उल्टे क्रम में तत्वों को एकत्र करता है:

public static <T> Collector<T, ?, Stream<T>> reversed() {
    return Collectors.collectingAndThen(Collectors.toList(), list -> {
        Collections.reverse(list);
        return list.stream();
    });
}

और इसे इस तरह से उपयोग करें:

Stream.of(1, 2, 3, 4, 5).collect(reversed()).forEach(System.out::println);

मूल उत्तर (एक बग होता है - यह समानांतर धाराओं के लिए सही ढंग से काम नहीं करता है):

एक सामान्य उद्देश्य स्ट्रीम रिवर्स विधि की तरह लग सकता है:

public static <T> Stream<T> reverse(Stream<T> stream) {
    LinkedList<T> stack = new LinkedList<>();
    stream.forEach(stack::push);
    return stack.stream();
}

2

विशुद्ध रूप से Java8 नहीं, लेकिन यदि आप संयोजन में अमरूद की Lists.reverse () विधि का उपयोग करते हैं, तो आप इसे आसानी से प्राप्त कर सकते हैं:

List<Integer> list = Arrays.asList(1,2,3,4);
Lists.reverse(list).stream().forEach(System.out::println);

2

एक रिवर्स उत्पन्न करने के विशिष्ट प्रश्न के संबंध में IntStream :

जावा 9 से शुरू होकर आप तीन-तर्क संस्करण का उपयोग कर सकते हैं IntStream.iterate(...):

IntStream.iterate(10, x -> x >= 0, x -> x - 1).forEach(System.out::println);

// Out: 10 9 8 7 6 5 4 3 2 1 0

कहाँ पे:

IntStream.iterate​(int seed, IntPredicate hasNext, IntUnaryOperator next);

  • seed - प्रारंभिक तत्व;
  • hasNext - धारा को समाप्त करने के लिए निर्धारित करने के लिए तत्वों पर लागू करने के लिए एक विधेय;
  • next - नए तत्व का उत्पादन करने के लिए पिछले तत्व पर लागू होने वाला फ़ंक्शन।

1

संदर्भ के लिए मैं उसी समस्या को देख रहा था, मैं रिवर्स ऑर्डर में स्ट्रीम तत्वों के स्ट्रिंग मूल्य में शामिल होना चाहता था।

itemList = {अंतिम, मध्य, प्रथम} => पहला, मध्य, अंतिम

मैं के साथ एक मध्यवर्ती संग्रह का उपयोग करने के लिए शुरू कर दिया collectingAndThenसे comonad या ArrayDequeके कलेक्टर स्टुअर्ट मार्क्स हालांकि मैं मध्यवर्ती संग्रह से खुश नहीं था, है, और फिर स्ट्रीमिंग

itemList.stream()
        .map(TheObject::toString)
        .collect(Collectors.collectingAndThen(Collectors.toList(),
                                              strings -> {
                                                      Collections.reverse(strings);
                                                      return strings;
                                              }))
        .stream()
        .collect(Collector.joining());

इसलिए मैंने स्टुअर्ट मार्क्स के उत्तर पर ध्यान Collector.ofदिया, जो कि कारखाने का उपयोग कर रहा था , जिसमें दिलचस्प फिनिशर लंबा है।

itemList.stream()
        .collect(Collector.of(StringBuilder::new,
                             (sb, o) -> sb.insert(0, o),
                             (r1, r2) -> { r1.insert(0, r2); return r1; },
                             StringBuilder::toString));

चूंकि इस मामले में धारा समानांतर नहीं है, कॉम्बिनेटर इतना प्रासंगिक नहीं है, मैं उपयोग कर रहा हूं insert कोड संगतता के लिए वैसे भी लेकिन इससे कोई फर्क नहीं पड़ता कि यह निर्भर करेगा कि स्ट्रिंगर पहले बनाया गया है।

मैंने StringJoiner को देखा, हालाँकि इसमें कोई insertविधि नहीं है ।


1

IntStream के साथ उलटने के विशिष्ट प्रश्न का उत्तर देना, मेरे लिए नीचे काम किया गया:

IntStream.range(0, 10)
  .map(x -> x * -1)
  .sorted()
  .map(Math::abs)
  .forEach(System.out::println);

1

ArrayDequeस्टैक या लिंक्डलिस्ट की तुलना में स्टैक में तेज हैं। "पुश ()" तत्वों को डेक्स के सामने सम्मिलित करता है

 protected <T> Stream<T> reverse(Stream<T> stream) {
    ArrayDeque<T> stack = new ArrayDeque<>();
    stream.forEach(stack::push);
    return stack.stream();
}

1

स्ट्रिंग या किसी ऐरे को उलट देना

(Stream.of("abcdefghijklm 1234567".split("")).collect(Collectors.collectingAndThen(Collectors.toList(),list -> {Collections.reverse(list);return list;}))).stream().forEach(System.out::println);

विभाजन को सीमांकक या अंतरिक्ष के आधार पर संशोधित किया जा सकता है


1

सबसे सरल समाधान का उपयोग कर रहा है List::listIteratorऔरStream::generate

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
ListIterator<Integer> listIterator = list.listIterator(list.size());

Stream.generate(listIterator::previous)
      .limit(list.size())
      .forEach(System.out::println);

यह जोड़ने योग्य है कि Stream.generate()अनंत धारा में उत्पन्न होता है, इसलिए यहां कॉल limit()बहुत महत्वपूर्ण है।
andreberate

0

यह मेरा इसे करने का तरीका है।

मुझे एक नया संग्रह बनाने और इसे पुनरावृत्त करने का विचार पसंद नहीं है।

IntStream # मानचित्र का विचार बहुत साफ-सुथरा है, लेकिन मैं IntStream # iterate पद्धति को पसंद करता हूं, क्योंकि मुझे लगता है कि शून्य से उलटी गिनती के विचार को iterate पद्धति के साथ बेहतर रूप से व्यक्त किया गया है और पीछे से सामने की ओर चलने के संदर्भ में समझने में आसान है।

import static java.lang.Math.max;

private static final double EXACT_MATCH = 0d;

public static IntStream reverseStream(final int[] array) {
    return countdownFrom(array.length - 1).map(index -> array[index]);
}

public static DoubleStream reverseStream(final double[] array) {
    return countdownFrom(array.length - 1).mapToDouble(index -> array[index]);
}

public static <T> Stream<T> reverseStream(final T[] array) {
    return countdownFrom(array.length - 1).mapToObj(index -> array[index]);
}

public static IntStream countdownFrom(final int top) {
    return IntStream.iterate(top, t -> t - 1).limit(max(0, (long) top + 1));
}

यह साबित करने के लिए यहां कुछ परीक्षण दिए गए हैं:

import static java.lang.Integer.MAX_VALUE;
import static org.junit.Assert.*;

@Test
public void testReverseStream_emptyArrayCreatesEmptyStream() {
    Assert.assertEquals(0, reverseStream(new double[0]).count());
}

@Test
public void testReverseStream_singleElementCreatesSingleElementStream() {
    Assert.assertEquals(1, reverseStream(new double[1]).count());
    final double[] singleElementArray = new double[] { 123.4 };
    assertArrayEquals(singleElementArray, reverseStream(singleElementArray).toArray(), EXACT_MATCH);
}

@Test
public void testReverseStream_multipleElementsAreStreamedInReversedOrder() {
    final double[] arr = new double[] { 1d, 2d, 3d };
    final double[] revArr = new double[] { 3d, 2d, 1d };
    Assert.assertEquals(arr.length, reverseStream(arr).count());
    Assert.assertArrayEquals(revArr, reverseStream(arr).toArray(), EXACT_MATCH);
}

@Test
public void testCountdownFrom_returnsAllElementsFromTopToZeroInReverseOrder() {
    assertArrayEquals(new int[] { 4, 3, 2, 1, 0 }, countdownFrom(4).toArray());
}

@Test
public void testCountdownFrom_countingDownStartingWithZeroOutputsTheNumberZero() {
    assertArrayEquals(new int[] { 0 }, countdownFrom(0).toArray());
}

@Test
public void testCountdownFrom_doesNotChokeOnIntegerMaxValue() {
    assertEquals(true, countdownFrom(MAX_VALUE).anyMatch(x -> x == MAX_VALUE));
}

@Test
public void testCountdownFrom_givesZeroLengthCountForNegativeValues() {
    assertArrayEquals(new int[0], countdownFrom(-1).toArray());
    assertArrayEquals(new int[0], countdownFrom(-4).toArray());
}

0

इस सब में मुझे वह उत्तर दिखाई नहीं दे रहा है जो मैं पहले जाता हूँ।

यह सवाल का सीधा जवाब नहीं है, लेकिन यह समस्या का एक संभावित समाधान है।

बस पहले स्थान पर पीछे की ओर सूची बनाएं। यदि आप कर सकते हैं, तो एक ArrayList के बजाय एक लिंक्डलिस्ट का उपयोग करें और जब आप आइटम जोड़ते हैं तो ऐड के बजाय "पुश" का उपयोग करें। सूची को रिवर्स ऑर्डर में बनाया जाएगा और फिर बिना किसी हेरफेर के सही ढंग से स्ट्रीम किया जाएगा।

यह उन मामलों में फिट नहीं होगा जहां आप आदिम सरणियों या सूचियों के साथ काम कर रहे हैं जो पहले से ही विभिन्न तरीकों से उपयोग किए जाते हैं लेकिन आश्चर्यजनक मामलों में अच्छी तरह से काम करते हैं।


0

यह विधि किसी भी स्ट्रीम के साथ काम करती है और जावा 8 का अनुपालन करती है:

Stream<Integer> myStream = Stream.of(1, 2, 3, 4, 5);
myStream.reduce(Stream.empty(),
        (Stream<Integer> a, Integer b) -> Stream.concat(Stream.of(b), a),
        (a, b) -> Stream.concat(b, a))
        .forEach(System.out::println);

-1

किसी सूची को उलटने का सबसे सामान्य और सबसे आसान तरीका होगा:

public static <T> void reverseHelper(List<T> li){

 li.stream()
.sorted((x,y)-> -1)
.collect(Collectors.toList())
.forEach(System.out::println);

    }

4
आप के अनुबंध का उल्लंघन करते हैं Comparator। परिणामस्वरूप कोई भी आपको गारंटी नहीं दे सकता है कि यह "ट्रिक" भविष्य के जावा संस्करण में किसी भी सॉर्टिंग एल्गोरिदम के साथ काम करेगा। एक ही चाल समानांतर धारा के लिए काम नहीं करती है, उदाहरण के लिए, समानांतर छँटाई एल्गोरिथ्म Comparatorअलग तरीके से उपयोग करता है। क्रमिक प्रकार के लिए यह संयोग से विशुद्ध रूप से काम करता है। मैं किसी को भी इस समाधान का उपयोग करने की सलाह नहीं दूंगा।
टैगिर वलेव

1
इसके अलावा जब आप सेट करते हैं तो यह काम नहीं करता हैSystem.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
टैगिर वालेव

मैंने सोचा था कि यह केवल रिवर्स ऑर्डर में चीजों को प्रिंट करने के क्रम में नहीं था (यानी अवरोही क्रम), और यह समानांतर धारा के साथ भी काम करता है: public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
parmeshwor11

1
प्रयास करें reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))(परिणाम हालांकि कोर की संख्या पर निर्भर हो सकता है)।
टैगिर वलेव

-1

जावा 8 ऐसा करने का तरीका:

    List<Integer> list = Arrays.asList(1,2,3,4);
    Comparator<Integer> comparator = Integer::compare;
    list.stream().sorted(comparator.reversed()).forEach(System.out::println);

4
यह रिवर्स ऑर्डर में छंटनी कर रहा है, एक सूची को वापस नहीं कर रहा है।
जोचेन बेडर्सडॉर्फ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.