জাভা 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আমি এই সংকলক ত্রুটি পেয়ে যাব

ত্রুটি: (১৯১, ০) এজেসি: sorted()ধরণের পদ্ধতিটি IntStreamআর্গুমেন্টের জন্য প্রযোজ্য নয় ( Integer::compare)

আমি এখানে কি মিস করছি?


1
একটির IntStreamকোন .sorted(Comparator)পদ্ধতি নেই; আপনাকে Stream<Integer>প্রথমটি IntStream
পেরোতে

ঠিক আছে, আমি এটি খুঁজে পেয়েছি, আপনার .boxed () এবং তারপরে .সোর্টড ()
ওয়াচ

4
IntStream.range(0, n)বিপরীত ক্রমে উত্পন্ন করতে , এমন কিছু করুন map(i -> n - i - 1)। বক্সিং এবং বাছাই করার দরকার নেই।
স্টুয়ার্ট

1
আপনার জেনারাল প্রশ্ন এবং আপনার নির্দিষ্ট প্রশ্নটি আমার কাছে দুটি সম্পূর্ণ আলাদা প্রশ্নের মতো পড়ে। জেনারেল স্ট্রিমটি বিপরীত করার কথা বলে, যখন নির্দিষ্টটি সংখ্যার ক্রমকে অর্ডার দেওয়ার কথা বলে। যদি স্ট্রিমটি একটি আনর্ডারড পদ্ধতিতে সংখ্যাগুলি তৈরি করে 1, 3, 2তবে আপনার প্রত্যাশিত ফলাফলটি কী? আপনি কি বিপরীত স্ট্রিম পছন্দ করেন?2, 3, 1 বা সাজানো স্ট্রিমের মতো চান 3, 2, 1?
চিককডোরো

8
আপনি সাধারণভাবে কোনও স্ট্রিমটিকে বিপরীত করতে পারবেন না - উদাহরণস্বরূপ একটি স্ট্রিম অসম্পূর্ণ হতে পারে।
অ্যাসিলিয়াস

উত্তর:


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পরিবর্তে এটির পরিবর্তে ব্যবহার করা ভাল , যা সম্মুখভাগে সন্নিবেশকে দক্ষতার সাথে সমর্থন করে। একটি ছোট ছোট বলি হ'ল আমরা ত্রি-আরগ ফর্মটি ব্যবহার করতে পারি না Stream.collect(); এটি দ্বিতীয় আরগের বিষয়বস্তুগুলি প্রথম আরগের সাথে একীভূত করা দরকার এবং সেখানে কোনও "অ্যাড-অল-এ-ফ্রন্ট" বাল্ক অপারেশন নেই Deque। পরিবর্তে, আমরা ব্যবহার করিaddAll() প্রথম আরগের সামগ্রীগুলি দ্বিতীয়টির শেষে যুক্ত এবং তারপরে আমরা দ্বিতীয়টি ফিরে আসি return এর জন্য 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});
}

দুর্দান্ত এবং সহজ এটি কি কিছু ওপেনসোর্স ইউটিলিটি থেকে? (এস্ট্রিমসের জিনিস) বা আপনার কোডের কিছু অংশ?
ওয়াচ

ধন্যবাদ! দুর্ভাগ্যক্রমে, আমি Estreamsনাম ফাঁস করার ইচ্ছা করি নি (আমি পোস্ট থেকে এটি সরিয়ে ফেলছি)। এটা তোলে আমাদের কোম্পানীর অভ্যন্তরীণ ইউটিলিটি ক্লাস, যা আমরা সম্পূরক ব্যবহার এক java.util.stream.Streamএর staticপদ্ধতি।
ব্র্যান্ডন

3
ঠিক আছে ... "দুর্দান্ত এবং সাধারণ"… এই সমাধানটি হ্যান্ডল করার কি কোনও ঘটনা আছে, যা স্টুয়ার্ট মার্কসের আরও সহজ সমাধান ইতিমধ্যে দেড় বছর আগে হ্যান্ডেল করেনি?
হলগার

আমি উপরের আমার পরীক্ষার পদ্ধতিতে কেবল তার সমাধানটি পরীক্ষা করেছি; এটা পাস। আমি যেমন করলাম তেমনভাবে আলিঙ্গন না করে অযথা ওভারফ্লো এড়ানো ছিলাম। আমি সম্মত যে তার চেয়ে ভাল। আমি প্রতিফলিত করতে আমার সম্পাদনা করব।
ব্র্যান্ডন

1
@ ওয়াচ, আপনি StreamExধাপটি নির্দিষ্ট করে ব্যবহার করতে পারেন :IntStreamEx.rangeClosed(from-1, to, -1)
তাগীর ভালিভ

34

সাধারণ প্রশ্ন:

স্ট্রিম কোনও উপাদান সংরক্ষণ করে না।

সুতরাং বিপরীত ক্রমে উপাদানগুলির পুনরাবৃত্তি কিছু মধ্যবর্তী সংগ্রহে উপাদানগুলি সংরক্ষণ না করেই সম্ভব নয়।

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

আপডেট: লিঙ্কযুক্ত তালিকাটিকে অ্যারেডিক (আরও ভাল) এ পরিবর্তিত হয়েছে বিশদটি দেখুন

ছাপে:

3

20

2

1

যাইহোক, sortপদ্ধতিটি যেমনটি সাজানো ঠিক তেমনি সঠিক নয়, বিপরীত হয় না (ধরে নিলে স্ট্রিমের অর্ডারযুক্ত উপাদান থাকতে পারে)

নির্দিষ্ট প্রশ্ন:

আমি এই সহজ, সহজ এবং স্বজ্ঞাত (কপিরাইট @ হোলার মন্তব্য ) পেয়েছি

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

3
কিছু স্ট্রিম অপারেশন, যেমন sortedএবং distinctপ্রকৃতপক্ষে একটি মধ্যবর্তী ফলাফল সংরক্ষণ করে। সে সম্পর্কে কিছু তথ্যের জন্য প্যাকেজ এপিআই ডক্স দেখুন ।
Lii

@ লিআই আমি No storageএকই পৃষ্ঠাতে দেখতে পাচ্ছি । এমনকি এটি স্টোর করে আমরা সেই স্টোরেজে অ্যাক্সেস পেতে পারি না (তাই No storageআমার ধারণা ঠিক আছে)
ভেঙ্কটা রাজু

ভাল উত্তর. তবে যেহেতু অতিরিক্ত স্থান ব্যবহার করা হয়, তাই প্রোগ্রামারদের পক্ষে খুব বড় সংগ্রহের ক্ষেত্রে আপনার পদ্ধতির ব্যবহার করা অনেকের পক্ষে দুর্দান্ত ধারণা নয় be
মনু মঞ্জুনাথ

আমি বোঝার দৃষ্টিকোণ থেকে সমাধানের সরলতা পছন্দ করি এবং বিদ্যমান ডাটা স্ট্রাকচারের উপর একটি বিদ্যমান পদ্ধতিটি উপকার করতে পারি ... মানচিত্রের প্রয়োগের সাথে পূর্ববর্তী সমাধানটি বোঝা আরও কঠিন তবে নিশ্চিতভাবে মানু সঠিক, বড় সংগ্রহের জন্য আমি এটি ব্যবহার করব না স্বজ্ঞাত, এবং উপরের মানচিত্রটি বেছে নেবে।
বিজার

এটি এখানে কয়েকটি সঠিক উত্তরের একটি। অন্যান্য ব্যক্তিদের বেশিরভাগই আসলে স্ট্রিমটিকে বিপরীত করে না, তারা কোনওভাবে এটি এড়াতে চেষ্টা করে (যা কেবলমাত্র পরিস্থিতিগুলির মধ্যে বিচিত্র সেটগুলির মধ্যে কাজ করে যার মধ্যে আপনি সাধারণত প্রথম স্থানে বিপরীত হওয়ার প্রয়োজন হয় না)। যদি আপনি এমন স্ট্রিমটিকে উল্টানোর চেষ্টা করেন যা মেমরির সাথে খাপ খায় না তবে আপনি যেভাবেই এটি ভুল করছেন। এটি একটি ডিবিতে ফেলে দিন এবং নিয়মিত এসকিউএল ব্যবহার করে বিপরীত স্ট্রিম পান।
কিউবিক

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>করে (ex। 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 -> ...)

আইটেমগুলি দক্ষতার সাথে সংগ্রহের জন্য তালিকার (তালিকার শেষে) এবং পেয়ারা তালিকাগুলি কার্যকর করার জন্য পেয়ারা তালিকাগুলি ব্যবহার করুন এবং আর একটি অনুলিপি না দিয়ে দক্ষতার সাথে পেয়ারা তালিকা সরবরাহ করুন।

কাস্টম সংগ্রহকারীর জন্য এখানে কয়েকটি পরীক্ষার মামলা রয়েছে:

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.reverse(Stream.of("1", "2", "20", "3"))
             .forEach(System.out::println);

এটি একটি অ্যারেলিস্টে সংগ্রহ করে এবং তারপরে তালিকার উপরের দিকে পুনরাবৃত্তি করতে, উভয় দিক দিয়ে পুনরাবৃত্তি করতে পারে এমন তালিকার তালিকা শ্রেণীর ব্যবহার করে কাজ করে।

আপনার যদি ইতিমধ্যে একটি তালিকা থাকে তবে এটি আরও দক্ষ হবে

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

1
এই প্রকল্পটি সম্পর্কে খুব ভাল জানা ছিল না
ওয়াচ

1
সাইক্লোপস এখন দক্ষ স্ট্রিম রিভার্সাল (বর্তমানে রেঞ্জ, অ্যারে এবং তালিকার জন্য) এর জন্য স্প্লিটেটরেটরদের সাথেও আসে । সাইক্লপ্স তৈরি করা হচ্ছে SequenceM SequenceM.of, SequenceM.range বা SequenceM.fromList সঙ্গে স্ট্রিম এক্সটেনশনটি স্বয়ংক্রিয়ভাবে দক্ষতার উলটাকর 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();

তারপরে comp তুলকগুলি ব্যবহার করে:

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

2
এটি কেবল আপনার "নির্দিষ্ট প্রশ্নের" উত্তর তবে আপনার "সাধারণ প্রশ্নের" নয়।
চিককডোরো

9
Collections.reverseOrder()জাভা 1.2 এর পরে থেকে বিদ্যমান এবং Integer...
হোলার

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) কাস্টম সংগ্রহকারীদের কাছে আবেদন। দুটোই একেবারেই অপ্রয়োজনীয়। অন্যথায়, এটি জেডিকে 8-তে কিছু গুরুতর ভাষা প্রকাশের ইস্যু সম্পর্কে সাক্ষ্য দিত। এবং আপনার উত্তরটি এর বিপরীতে প্রমাণ করে :)
ভিট্রামস

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

দ্রষ্টব্য আপনি দ্রুত অন্য ধরণের স্ট্রিমগুলিতে (ইনটস্ট্রিম, ...) প্রসারিত করতে পারেন।

পরীক্ষামূলক:

// 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

নিখুঁতভাবে জাভা 8 নয় তবে আপনি যদি পেয়ারা এর তালিকাভুক্ত পদ্ধতি ব্যবহার করেন তবে আপনি সহজেই এটি অর্জন করতে পারেন:

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

রেফারেন্সের জন্য আমি একই সমস্যার দিকে চেয়ে ছিলাম, আমি বিপরীত ক্রমে স্ট্রিম উপাদানগুলির স্ট্রিং মানটিতে যোগ দিতে চাইছিলাম।

আইটেমলিস্ট = {শেষ, মাঝারি, প্রথম} => প্রথম, মাঝারি, শেষ

আমি এতে একটি অন্তর্বর্তী সংগ্রহে ব্যবহার শুরু 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 কোডের ধারাবাহিকতার জন্য যাইহোক তবে কোন স্ট্রিংবিল্ডারটি প্রথমে নির্মিত তা নির্ভর করে এটি কোনও বিষয় নয়।

আমি স্ট্রিংজাইনারের দিকে তাকালাম তবে এর কোনও insertপদ্ধতি নেই।


1

ইনটস্ট্রিমের সাথে বিপরীতকরণের নির্দিষ্ট প্রশ্নের উত্তর দেওয়া, নীচে আমার পক্ষে কাজ করেছে:

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এবং andStream::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()খুব গুরুত্বপূর্ণ।
অ্যান্ড্রেব্রিট

0

এইভাবেই আমি এটি করি।

আমি একটি নতুন সংগ্রহ তৈরির ধারণাটি পছন্দ করি না এবং এটি পুনরাবৃত্তি করি।

ইন্টস্ট্রিম # মানচিত্রের ধারণাটি বেশ ঝরঝরে, তবে আমি ইন্টারস্ট্রিম # পুনরাবৃত্ত পদ্ধতিটি পছন্দ করি, কারণ আমি মনে করি যে জিরোর একটি কাউন্টডাউন ধারণাটি পুনরাবৃত্ত পদ্ধতির সাথে আরও ভালভাবে প্রকাশ করা হয়েছে এবং অ্যারেটিকে পিছন থেকে সামনের দিকে চলার ক্ষেত্রে বোঝা সহজ।

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

এই সমস্ত কিছুর মধ্যে আমি উত্তরটি দেখতে পাচ্ছি না আমি প্রথমে যাব।

এটি ঠিক কোনও প্রশ্নের সরাসরি উত্তর নয়, তবে এটি সমস্যার সম্ভাব্য সমাধান।

প্রথমদিকে প্রথম দিকে কেবল তালিকাটি তৈরি করুন। যদি আপনি পারেন তবে অ্যারেলিস্টের পরিবর্তে একটি লিঙ্কযুক্তলিস্ট ব্যবহার করুন এবং আপনি আইটেমগুলি যুক্ত করার সময় অ্যাডের পরিবর্তে "পুশ" ব্যবহার করুন। তালিকাটি বিপরীত ক্রমে নির্মিত হবে এবং তারপরে কোনও হেরফের ছাড়াই সঠিকভাবে প্রবাহিত হবে।

আপনি যে আদিম অ্যারে বা তালিকাগুলি ইতিমধ্যে বিভিন্ন উপায়ে ব্যবহার করেছেন তবে সেই বিস্ময়কর সংখ্যক ক্ষেত্রে ভাল কাজ করে এমন ক্ষেত্রে এটি মাপসই হবে না।


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); }
উতরিত

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
এটি বিপরীতে ক্রম অনুসারে বাছাই করছে, কোনও তালিকা পুনরায় না ফেরাচ্ছে।
জোচেন বেডারসর্ডার
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.