Java 8 akış ters sırası


153

Genel soru: Bir akışı tersine çevirmenin doğru yolu nedir? Akışın ne tür unsurlardan oluştuğunu bilmediğimizi varsayarsak, herhangi bir akışı tersine çevirmenin genel yolu nedir?

Özel soru:

IntStreambelirli bir aralıkta Tamsayılar oluşturmak için aralık yöntemi sağlar IntStream.range(-range, 0), şimdi 0'dan negatife geçiş aralığını tersine çevirmek istiyorum, ayrıca kullanamıyorumInteger::compare

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

ile IntStreamderleyici hatası alıyorum

Hata: (191, 0) ajc: yöntem sorted()türü IntStream(bağımsız değişkenler için geçerli değildir Integer::compare)

burada ne eksik?


1
An'ın yöntemi IntStreamyoktur .sorted(Comparator); Stream<Integer>bir IntStream
14

Tamam, buldum, .boxed () ve sonra .sorted ()
vach

4
Bir IntStream.range(0, n)ters sırayla oluşturmak için map(i -> n - i - 1). Boks ve sıralama yapmaya gerek yok.
Stuart Marks

1
Genel sorunuz ve özel sorunuz bana iki farklı soru gibi okunuyor. Genel, akışı tersine çevirmekten bahsederken , spesifik olarak sayıları azalan sırada sıralamaktan bahseder. Eğer akış sayıları sırasız bir şekilde üretiyorsa, 1, 3, 2beklenen sonuç nedir? Ters çevrilmiş akışı 2, 3, 1veya sıralanmış akışı beğenmek ister 3, 2, 1misiniz?
chiccodoro

8
Bir akışı genel olarak tersine çeviremezsiniz; örneğin, bir akış sonsuz olabilir.
assylias

Yanıtlar:


78

Bunun tersini oluşturma sorusu için şöyle bir IntStreamşey deneyin:

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

Bu boks ve ayıklamayı önler.

Herhangi bir türdeki bir akışı nasıl tersine çevireceğimize dair genel soru için, "uygun" bir yol olduğunu bilmiyorum. Düşünebileceğim birkaç yol var. Her ikisi de akış öğelerini depolar. Öğeleri saklamadan bir akışı tersine çevirmenin bir yolunu bilmiyorum.

Bu ilk yol, öğeleri bir dizide saklar ve ters sırada bir akışa okur. Akış öğelerinin çalışma zamanı türünü bilmediğimizden, diziyi düzgün bir şekilde yazamadığımızı ve denetlenmeyen bir döküm gerektirdiğini unutmayın.

@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]);
}

Başka bir teknik, öğeleri ters çevrilmiş bir listede toplamak için toplayıcıları kullanır. Bu, ArrayListnesnelerin önünde çok sayıda ekleme yapar , bu nedenle çok sayıda kopyalama devam eder.

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

Muhtemelen bir çeşit özelleştirilmiş veri yapısı kullanarak çok daha verimli bir ters toplayıcı yazmak mümkündür.

GÜNCELLEME 2016-01-29

Bu soru son zamanlarda biraz ilgi gördüğü için, ön tarafa yerleştirme ile ilgili sorunu çözmek için cevabımı güncellemeliyim ArrayList. Bu, O (N ^ 2) kopyalamayı gerektiren çok sayıda elemanla korkunç derecede verimsiz olacaktır.

ArrayDequeÖnde yerleştirmeyi etkili bir şekilde destekleyen bir bunun yerine kullanılması tercih edilir . Küçük bir kırışıklık şu üç arg biçimini kullanamayız Stream.collect(); ikinci argümanın içeriğinin ilk argümanla birleştirilmesini gerektirir ve "önden ekle" toplu işlem yapılmaz Deque. Bunun yerine, addAll()birinci argümanın içeriğini ikincinin sonuna eklemek için kullanırız ve sonra ikinciyi döndürürüz. Bunun için Collector.of()fabrika yönteminin kullanılması gerekir .

Kodun tamamı şudur:

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

Sonuç, a Dequeyerine kullanılır List, ancak artık tersine çevrilmiş sırada kolayca yinelenebileceği veya yayınlanabileceği için bu çok fazla bir sorun olmamalıdır.


15
Alternatif:IntStream.iterate(to-1, i->i-1).limit(to-from)
Holger

2
@Holger Maalesef, bu çözüm taşmayı doğru şekilde işlemiyor.
Brandon

2
@Brandon Mintern: aslında .limit(endExcl-(long)startIncl)bunun yerine kullanmak zorunda kalacaksınız , ancak böyle büyük akışlar için, rangetemel çözümden çok daha az verimli olduğu için yine de çok cesaretini kırıyor . Yorum yazarken verimlilik farkının farkında değildim.
Holger

48

Zarif çözüm

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
Zarif ama liste elemanlarının olması gerektiği gibi tam olarak çalışmıyor Comparable...
Krzysztof Wolny

26
Bu, öğelerin ters sırada sıralanmasını istediğimizi varsayar . Soru, bir akışın sırasını tersine çevirmektir.
Dillon Ryan Redding

37

Buradaki çözümlerin çoğu sıralama veya tersine çevirir IntStream, ancak bu gereksiz yere ara depolama gerektirir. Stuart Marks'ın çözümü :

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

Bu testi geçerek taşmayı da doğru şekilde işler:

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

harika ve basit. Bu bazı açık kaynaklardan yararlanıyor mu? (Estreams olayı) veya kodunuzun bir parçası?
vach

Teşekkürler! Ne yazık ki, Estreamsadı sızdırmak niyetinde değilim ( postadan kaldıracağım). Biz takviyesi amacıyla kullandığımız şirket dahili yarar sınıfları, biri java.util.stream.Stream'nin staticyöntemlerle.
Brandon

3
Tamam… “harika ve basit”… Stuart Marks'ın daha basit çözümünün zaten bir buçuk yıldan fazla bir süre önce ele almadığı bu çözümün ele aldığı herhangi bir durum var mı ?
Holger

Çözümünü yukarıdaki test yöntemimle test ettim; geçer. Onun gibi onu kucaklamak yerine taşmadan kaçınıyordum. Onun daha iyi olduğuna katılıyorum. Bunu yansıtmak için benimkini değiştireceğim.
Brandon

1
@vach, StreamExadımı belirterek kullanabilirsiniz :IntStreamEx.rangeClosed(from-1, to, -1)
Tagir Valeev

34

Genel Soru:

Akış hiçbir öğeyi saklamaz.

Bu nedenle, bazı ara koleksiyonlarda öğeler saklanmadan, ters sırada yinelenen öğeler mümkün değildir.

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

Güncelleme: LinkedList'i ArrayDeque olarak değiştirdi (daha iyi) ayrıntılar için buraya bakın

Baskılar:

3

20

2

1

Bu arada, sortyöntem kullanımı sıralandığı gibi doğru değil, tersine DEĞİL (akışın sırasız öğelere sahip olabileceği varsayılarak)

Özel Soru:

Bunu basit, daha kolay ve sezgisel buldum (Kopyalanan @Holger yorumu )

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

3
Bir ara sonuç gibi sortedve distinctfiilen saklayan bazı akış işlemleri . Bununla ilgili bazı bilgiler için API belgeleri paketine bakın .
Lii

@Lii No storageAynı sayfada görüyorum . Mağazalar bile bu depolamaya erişemiyoruz ( No storagesanırım para cezası)
Venkata Raju

İyi cevap. Ancak fazladan alan kullanıldığından, programcıların yaklaşımınızı çok büyük koleksiyonlarda kullanmaları pek iyi bir fikir değildir.
Manu Manjunath

Çözümün basitliğini anlaşılabilir bir perspektiften seviyorum ve mevcut bir veri yapısında mevcut bir yöntemi kullanıyorum ... bir harita uygulaması ile önceki çözümü anlamak daha zordur, ancak kesinlikle Manu doğru, büyük koleksiyonlar için bunu kullanmam sezgiseldir ve yukarıdaki haritayı seçer.
Beezer

Buradaki birkaç doğru cevaptan biri. Diğerlerinin çoğu gerçekte akışı tersine çevirmez, bir şekilde yapmaktan kaçınmaya çalışırlar (bu sadece normalde ilk başta tersine çevirmeniz gerekmeyen garip koşullar altında çalışır). Belleğe sığmayan bir akışı tersine çevirmeye çalışırsanız, yine de yanlış yapıyorsunuz demektir. Bir DB içine dökün ve normal SQL kullanarak ters akışı elde edin.
Kübik

19

harici lib olmadan ...

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

Uygulanırsa Comparable<T>(örn. Integer, String, Date), Kullandığınız bunu yapabilirsiniz Comparator.reverseOrder().

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

6
Bu akışı tersine çevirmez. Akışı ters sırayla sıralar. Eğer Stream.of(1,3,2)sonuç olmasaydı Stream.of(3,2,1)DEĞİLStream.of(2,3,1)
wilmol

12

Elemanları ters sırada toplayan kendi toplayıcınızı tanımlayabilirsiniz:

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

Ve şöyle kullanın:

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

Öğeleri (listenin sonunda) verimli bir şekilde toplamak için bir ArrayList kullanın ve Guava Lists.Listenin başka bir kopyasını çıkarmadan listenin tersine çevrilmiş bir görünümünü verimli bir şekilde vermek için ters çevirin.

Özel koleksiyoncu için bazı test örnekleri:

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

cyclops - reat StreamUtils, ters bir Stream yöntemine ( javadoc ) sahiptir.

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

Bir ArrayList'e toplayıp, her iki yönde yineleyebilen ListIterator sınıfını kullanarak, liste üzerinde geriye doğru yineleme yaparak çalışır.

Zaten bir Listeniz varsa, daha verimli olacaktır

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

1
Bu proje hakkında güzel bir şey bilmiyordum
vach

1
cyclops artık verimli Akış geri dönüşü için Ayırıcılar ile birlikte geliyor (şu anda Aralıklar, diziler ve Listeler için). SequenceM.of, SequenceM.range veya SequenceM.fromList ile cyclops SequenceM Stream uzantısı oluşturmak , verimli bir şekilde geri dönüşümlü ayırıcılardan otomatik olarak faydalanır.
John McClean

6

JOOλ kullanmanızı öneririm , Java 8 akışlarına ve lambdas'a birçok kullanışlı işlevsellik ekleyen harika bir kütüphane.

Ardından aşağıdakileri yapabilirsiniz:

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

Bu kadar basit. Oldukça hafif bir kütüphane ve herhangi bir Java 8 projesine eklemeye değer.


5

İşte bulduğum çözüm:

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

sonra bu karşılaştırıcıları kullanarak:

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

2
Bu sadece "özel sorunuza" bir cevaptır, "genel sorunuza" değil.
chiccodoro

9
Collections.reverseOrder()Java 1.2'den beri var ve Integer… ile çalışıyor …
Holger

4

Bu yardımcı yöntem nasıl?

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

Yinelenmeden tüm vakalarla çalışıyor gibi görünüyor.


Bu çözümü çok seviyorum. Çoğu cevap iki kategoriye ayrılır: (1) Koleksiyonu tersine çevirin ve .stream (), (2) Özel koleksiyonculara hitap edin. Her ikisi de kesinlikle gereksiz. Aksi takdirde, JDK 8'in kendisinde bazı ciddi dil ifade sorunu hakkında tanıklık ederdi. Ve cevabınız bunun tam tersini kanıtlıyor :)
vitrumlar

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

3

En basit yol (basit toplama - paralel akışları destekler):

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

Gelişmiş yol (paralel akışları sürekli olarak destekler):

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

Hızlı bir şekilde diğer akış türlerine (IntStream, ...) genişletebileceğinizi unutmayın.

Test yapmak:

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

Sonuçlar:

Six
Five
Four
Three
Two
One

Ek notlar:simplest way Diğer akışı operasyonları ile kullanıldığında bu kadar kullanışlı değildir (ödemeli sonlarını paralellik katılmak). Bu advance waysorun yok ve örneğin akışın başlangıç ​​özelliklerini de koruyor SORTEDve bu nedenle, tersinden sonra diğer akış işlemleriyle birlikte kullanmanın yolu.


2

Biri, öğeleri ters sırada toplayan bir toplayıcı yazabilir:

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

Ve şu şekilde kullanın:

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

Orijinal cevap (bir hata içerir - paralel akışlar için düzgün çalışmıyor):

Genel amaçlı bir ters akım yöntemi şöyle görünebilir:

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

2

Yalnızca Java8 değil, birlikte guava'nın Lists.reverse () yöntemini birlikte kullanıyorsanız, bunu kolayca başarabilirsiniz:

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

2

Tersine çevirme özel sorusu ile ilgili olarak IntStream :

Java 9'dan başlayarak aşağıdakilerin üç bağımsız değişken sürümünü kullanabilirsiniz 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

nerede:

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

  • seed - başlangıç ​​elemanı;
  • hasNext - akışın ne zaman sona ermesi gerektiğini belirlemek için öğelere uygulanacak bir yüklem;
  • next - yeni bir eleman üretmek için önceki öğeye uygulanacak bir işlev.

1

Başvuru için aynı soruna bakıyordu, tersine akış öğelerinin dize değerini katılmak istedim.

itemList = {son, orta, ilk} => ilk, orta, son

Birlikte bir ara koleksiyon kullanmaya başladı collectingAndThendan comonad ya ArrayDequeait toplayıcı Stuart Marks Ben orta koleksiyonu ile mutlu olmamasına rağmen, ve yine akışı

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

Bu yüzden Collector.of, ilginç bitirici lambda'ya sahip olan fabrikayı kullanan Stuart Marks cevabını yineledim.

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

Bu durumda akış paralel olmadığından, birleştirici o kadar alakalı değil, insertyine de kod tutarlılığı uğruna kullanıyorum , ancak ilk olarak hangi stringbuilder'ın inşa edildiğine bağlı olacağı önemli değil.

Ancak bir insertyöntemi yok StringJoiner baktı .


1

IntStream ile tersine dönme ile ilgili belirli bir soruya cevap vermek, aşağıda benim için çalıştı:

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

1

ArrayDequeyığın içinde bir Yığın veya LinkedList'ten daha hızlıdır. "push ()" öğeleri Deque öğesinin önüne ekler

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

1

Ters dize veya herhangi bir Dizi

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

bölme ayırıcı veya boşluk temelinde değiştirilebilir


1

en basit çözüm kullanıyor List::listIteratorveStream::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()Sonsuz akışta üretilen eklemeye değer , bu nedenle burada çağrı limit()çok önemlidir.
andrebrait

0

Ben böyle yaparım.

Yeni bir koleksiyon oluşturma ve tersine çevirme fikrinden hoşlanmıyorum.

IntStream # harita fikri oldukça düzgün, ancak IntStream # iterate yöntemini tercih ediyorum, çünkü sıfır için geri sayım fikrinin yineleme yöntemi ile daha iyi ifade edildiğini ve dizinin arkadan öne doğru yürümesi açısından daha kolay olduğunu düşünüyorum.

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

İşte işe yaradığını kanıtlamak için bazı testler:

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

Bunların hepsinde ilk olarak alacağım yanıtı göremiyorum.

Bu tam olarak soruya doğrudan bir cevap değildir, ancak soruna potansiyel bir çözümdür.

İlk olarak listeyi geriye doğru yapmanız yeterlidir. Yapabiliyorsanız, bir ArrayList yerine LinkedList kullanın ve öğe eklediğinizde add yerine "Push" kullanın. Liste ters sırayla oluşturulacak ve daha sonra herhangi bir manipülasyon olmadan doğru şekilde akacaktır.

Bu, zaten çeşitli şekillerde kullanılan ancak şaşırtıcı sayıda durumda iyi çalışan ilkel diziler veya listelerle uğraştığınız durumlara uymayacaktır.


0

Bu yöntem herhangi bir Stream ile çalışır ve Java 8 uyumludur:

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

Bir listeyi tersine çevirmenin en genel ve en kolay yolu:

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

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

    }

4
Sözleşmesini ihlal ediyorsunuz Comparator. Sonuç olarak hiç kimse size bu "numara" herhangi bir sıralama algoritması ile gelecekteki herhangi bir Java sürümü çalışacağını garanti edemez. Aynı hile paralel akış için çalışmaz, örneğin, paralel sıralama algoritması Comparatorfarklı şekillerde kullanır . Sıralı sıralama için tamamen tesadüfen çalışır. Kimsenin bu çözümü kullanmasını önermem.
Tagir Valeev

1
Ayrıca ayarladığınızda da çalışmıyorSystem.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
Tagir Valeev

Ben sadece ters sırayla şeyler ters sırada (yani azalan sırada) yazdırmak hakkında olduğunu düşündüm, ve paralel akışı ile de çalışır:public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
parmeshwor11

1
Deneyin reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))(sonuç, çekirdek sayısına bağlı olabilir).
Tagir Valeev

-1

Bunu yapmanın Java 8 yolu:

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

4
Bu, bir listeyi geri döndürmek yerine tersine sıralamaktır.
Jochen Bedersdorfer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.