자바 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
FGE을

좋아, 내가 그것을 발견했습니다, 당신은 (.boxed) 다음 () .sorted 사용할 필요가
vach

4
IntStream.range(0, n)역순으로 생성하려면 다음과 같이하십시오 map(i -> n - i - 1). 권투와 정렬을 할 필요가 없습니다.
스튜어트 마크

1
당신의 일반적인 질문과 당신의 특정한 질문은 나에게 완전히 다른 두 질문처럼 읽 힙니다. 장군은 시내 를 거꾸로 하는 것을 말하고, 구체적으로는 주문 번호를 내림차순으로 말한다. 스트림이와 같이 순서가없는 방식으로 숫자를 생성하는 경우 1, 3, 2예상되는 결과는 무엇입니까? 반전 된 스트림 2, 3, 1또는 정렬 된 스트림을 원 3, 2, 1하십니까?
chiccodoro

8
일반적으로 스트림을 되돌릴 수 없습니다. 예를 들어 스트림이 무한 할 수 있습니다.
assylias

답변:


78

reverse 생성에 대한 특정 질문에 대해서는 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 . 이것은 많은 요소로 인해 비효율적이며 O (N ^ 2) 복사가 필요합니다.

ArrayDeque전면의 삽입을 효율적으로 지원 하는 대신 대신 사용하는 것이 좋습니다. 작은 주름은 우리가 3 중 형태를 사용할 수 없다는 것입니다 Stream.collect(). 두 번째 arg의 내용을 첫 번째 arg로 병합해야하며에 "앞에 추가"대량 작업이 없습니다 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
@Holger 불행히도이 솔루션은 오버플로를 올바르게 처리하지 못합니다.
Brandon

2
@Brandon Mintern : 실제로 .limit(endExcl-(long)startIncl)대신 대신 사용해야 하지만 이러한 큰 스트림의 경우 range기반 솔루션 보다 효율성이 떨어 지므로 매우 권장하지 않습니다 . 의견을 쓸 당시에는 효율성 차이에 대해 알지 못했습니다.
Holger

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...
Krzysztof Wolny

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 것) 또는 코드 조각?
vach

감사! 불행히도, 나는 Estreams이름 을 유출하려고하지 않았습니다 (포스트에서 이름을 제거 할 것입니다). 그것은 우리가 보충에 사용하는 우리 회사의 내부 유틸리티 클래스의 하나 java.util.stream.Streamstatic방법.
Brandon

3
좋아요…“굉장하고 간단합니다 ……이 솔루션이 처리하는 사례가 있습니까? Stuart Marks의 훨씬 간단한 솔루션 이 이미 1 년 반 전에 처리하지 않았습니까?
Holger

방금 위의 테스트 방법으로 솔루션을 테스트했습니다. 통과합니다. 필자가했던 것처럼 오버플로를 불필요하게 피하는 것이 었습니다. 나는 그의 것이 더 낫다는 데 동의합니다. 이를 반영하기 위해 내 것을 편집하겠습니다.
Brandon

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

업데이트 : LinkedList를 ArrayDeque로 변경했습니다 (더 나은) 자세한 내용은 여기를 참조하십시오

인쇄물:

3

20

2

1

그건 그렇고, 방법을 사용 sort하면 정렬 할 때 정확하지 않으며 반대는 아닙니다 (스트림에 정렬되지 않은 요소가 있다고 가정)

구체적인 질문 :

이 간단하고 쉽고 직관적 인 것을 발견했습니다 (@Holger 의견 복사 )

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

3
중간 결과 sorted와 같은 일부 스트림 작업은 distinct실제로 중간 결과를 저장합니다. 이에 대한 정보 는 패키지 API 문서 를 참조하십시오 .
Lii

@Lii No storage같은 페이지에 표시됩니다. 심지어 우리가 해당 스토리지에 액세스 할 수 없습니다 저장 (그래서 No storage내가 생각 괜찮습니다)
벤 카타 라주

좋은 대답입니다. 그러나 여분의 공간이 사용되므로 프로그래머가 대규모 컬렉션에서 접근 방식을 사용하는 것은 좋은 생각이 아닙니다.
Manu Manjunath

나는 이해의 관점에서 솔루션의 단순함을 좋아하고 기존 데이터 구조에서 기존 방법을 활용합니다 ...지도 구현으로 된 이전 솔루션은 이해하기 어렵지만 Manu가 옳습니다. 대규모 컬렉션의 경우 이것을 사용하지 않을 것입니다 직관적이고 위의지도를 선택합니다.
Beezer

이것은 몇 가지 정답 중 하나입니다. 대부분의 다른 스트림은 실제로 스트림을 되 돌리지 않습니다. 어떻게 든 스트림을 피하려고합니다 (일반적으로 처음에는 되돌릴 필요가없는 독특한 상황에서만 작동합니다). 메모리에 맞지 않는 스트림을 되돌리려 고하면 어쨌든 잘못하고 있습니다. DB에 덤프하고 일반 SQL을 사용하여 리버스 스트림을 얻으십시오.
Cubic

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)NOTStream.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를 앞으로 사용하고 Guava 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

cyclops-react StreamUtils에는 리버스 스트림 메소드 ( javadoc )가 있습니다.

  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
cyclops에는 효율적인 스트림 반전 (현재 범위, 배열 및 목록)을위한 Spliterator 도 제공됩니다 . SequenceM.of, SequenceM.range 또는 SequenceM.fromList를 사용하여 cyclops SequenceM 스트림 확장을 만들면 자동으로 가역적 인 스플리터를 활용할 수 있습니다.
John McClean

6

jOOλ를 사용하는 것이 좋습니다.이 라이브러리는 Java 8 스트림과 람다에 유용한 기능을 많이 추가하는 훌륭한 라이브러리입니다.

그런 다음 다음을 수행 할 수 있습니다.

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

그렇게 간단합니다. 매우 가벼운 라이브러리이며 Java 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
이것은 "특정 질문"에 대한 답변 일뿐 "일반적인 질문"에 대한 답변은 아닙니다.
chiccodoro

9
Collections.reverseOrder()Java 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);
}

중복없이 모든 경우에 작동하는 것 같습니다.


나는이 솔루션을 많이 좋아합니다. 대부분의 답변은 두 가지 카테고리로 나뉩니다. 둘 다 절대적으로 필요하지 않습니다. 그렇지 않으면 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은 아니지만 guava의 Lists.reverse () 메소드를 함께 사용하면 다음과 같이 쉽게 달성 할 수 있습니다.

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

2

역전을 일으키는 구체적인 질문과 관련하여 IntStream:

Java 9 부터 다음과 같은 3 가지 인수 버전을 사용할 수 있습니다 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 = {마지막, 중간, 첫 번째} => 첫 번째, 중간, 마지막

중간 컬렉션에 만족하지 않았지만 다시 수집하거나 스트리밍하지 않고 코나드 또는 Stuart Marks 수집기 collectingAndThen에서 중간 컬렉션을 사용하기 시작 했습니다.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 어쨌든 코드 일관성을 위해 하고 있지만 어떤 stringbuilder가 먼저 빌드되는지에 달려 있기 때문에 중요하지 않습니다.

StringJoiner를 보았지만 insert메소드 가 없습니다 .


1

아래의 IntStream으로 리버스에 대한 특정 질문에 대답하면 아래에서 효과가 있습니다.

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

1

ArrayDeque스택 또는 링크 된 목록보다 스택에서 더 빠릅니다. "push ()"는 Deque의 앞에 요소를 삽입합니다

 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()은 매우 중요합니다.
andrebrait

0

이것이 내가하는 방법입니다.

새 컬렉션을 만들고 반대로 반복한다는 아이디어가 마음에 들지 않습니다.

IntStream # map 아이디어는 매우 깔끔하지만 IntStream # iterate 메소드를 선호합니다. 카운트 다운 아이디어가 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

이 모든 것에서 나는 내가 먼저 갈 대답을 보지 못한다.

이것은 질문에 대한 직접적인 대답은 아니지만 문제에 대한 잠재적 인 해결책입니다.

먼저 목록을 거꾸로 만드십시오. 가능하면 ArrayList 대신 LinkedList를 사용하고 항목을 추가 할 때는 add 대신 "Push"를 사용하십시오. 목록은 역순으로 작성되며 조작없이 올바르게 스트리밍됩니다.

이미 다양한 방법으로 사용되었지만 놀라운 수의 경우에는 잘 작동하는 기본 배열 또는 목록을 처리하는 경우에는 적합하지 않습니다.


0

이 방법은 모든 스트림에서 작동하며 Java 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. 결과적으로이 "트릭"이 향후 Java 버전에서 정렬 알고리즘과 함께 작동 할 것이라고 아무도 보증 할 수 없습니다. 예를 들어 병렬 정렬 알고리즘 Comparator이 다른 방식으로 사용하는 것과 같은 병렬 스트림에는 동일한 트릭이 작동하지 않습니다 . 순차 정렬의 경우 순전히 우연히 작동합니다. 이 솔루션을 사용하는 사람은 권장하지 않습니다.
Tagir Valeev 8

1
또한 설정하면 작동하지 않습니다System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
Tagir Valeev

나는 그것이 정렬 된 순서가 아닌 역순으로 물건을 인쇄하는 것에 관한 것이라고 생각했고 (예 : 내림차순) 병렬 스트림에서도 작동합니다. 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()))(결과는 코어 수에 따라 다를 수 있습니다).
Tagir Valeev

-1

Java 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
목록을 되 돌리지 않고 역순으로 정렬합니다.
Jochen Bedersdorfer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.