Java 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 2014年

4
要生成IntStream.range(0, n)相反的顺序,请执行map(i -> n - i - 1)。无需装箱和分类。
Stuart Marks 2014年

1
您的总体问题和特定问题对我来说就像两个完全不同的问题。一般讲反转的,而比降序排序数字说话。如果流以无序方式生成数字,例如1, 3, 2,您的预期结果是什么?您要反转流一样2, 3, 1还是排序流一样3, 2, 1
chiccodoro 2014年

8
通常,您不能反转流-例如,流可能是无限的。
assylias 2014年

Answers:


78

对于产生反向的特定问题IntStream,请尝试如下操作:

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

这样可以避免装箱和分类。

对于如何反转任何类型的流的一般问题,我不知道有一种“正确”的方法。我可以想到几种方法。两者最终都存储了流元素。我不知道在不存储元素的情况下反转流的方法。

第一种方法将元素存储到数组中,然后以相反的顺序将它们读出到流中。请注意,由于我们不知道stream元素的运行时类型,因此我们无法正确键入数组,这需要未经检查的强制转换。

@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有效支持正面插入的。一个小皱纹是我们不能使用的三参数形式Stream.collect();它要求将第二个arg的内容合并到第一个arg中,并且在上没有“全部添加” Deque。相反,我们使用addAll()将第一个arg的内容附加到第二个arg的末尾,然后返回第二个。这需要使用Collector.of()工厂方法。

完整的代码是这样的:

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

结果是a Deque而不是a List,但这不是什么大问题,因为它可以轻松地以现在相反的顺序进行迭代或流式传输。


15
或者:IntStream.iterate(to-1, i->i-1).limit(to-from)
Holger 2014年

2
@Holger不幸的是,该解决方案无法正确处理溢出。
布兰登

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,但这不必要地需要中间存储。Stuart Marks的解决方案解决之道:

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的事情)还是您的某些代码?
2016年

谢谢!不幸的是,我无意泄露这个Estreams名字(我将从职位中删除它)。这是我们公司内部的实用程序类之一,可用来补充java.util.stream.Streamstatic方法。
布兰登

3
好吧……“很棒且简单”……这种解决方案是否可以处理,而Stuart Marks甚至更简单的解决方案在一年半之前还没有解决?
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);

更新:将LinkedList更改为ArrayDeque(更好),请参见此处以了解详细信息

印刷品:

3

20

2

1

顺便说一句,using sort方法在排序时是不正确的,不是反向的(假设流中可能有无序的元素)

具体问题:

我发现这个简单,容易和直观(复制@Holger 评论

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

3
一些流操作,例如sorteddistinct实际存储中间结果。有关此信息,请参阅软件包API文档
2014年

No storage在同一页上看到@Lii 。即使是存储,我们也无法访问该存储(所以No storage我想很好)
Venkata Raju 2015年

好答案。但是,由于使用了额外的空间,因此对于程序员来说,在非常大的集合中使用您的方法并不是一个好主意。
Manu Manjunath 2015年

从可理解性的角度来看,我喜欢该解决方案的简单性,并在现有的数据结构上利用现有的方法...以前使用map实现的解决方案更难理解,但可以肯定Manu是正确的,对于大型集合,我不会使用它直观,并且会选择上面的地图。
Beezer

这是这里的少数正确答案之一。其他大多数对象实际上并没有反转流,而是尝试避免以某种方式进行处理(这仅在特殊情况下才起作用,在这种情况下,您通常通常不需要首先反转)。如果您尝试逆转不适合内存的流,那么无论如何它都是错误的。将其转储到数据库中,并使用常规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>(例如,IntegerStringDate),你可以用做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来有效地插入收集项(在列表的末尾),而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具有反向Stream方法(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
尼斯不知道这个项目
2015年

1
独眼巨人现在还带有分离器,可进行有效的流逆转(当前用于范围,数组和列表)。使用SequenceM.of,SequenceM.range或SequenceM.fromList 创建独眼巨人SequenceM流扩展将自动利用有效的可逆分离器。
约翰·麦克林

6

我建议使用jOOλ,它是一个很棒的库,为Java 8流和lambda添加了许多有用的功能。

然后,您可以执行以下操作:

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 2014年

9
Collections.reverseOrder()自Java 1.2起就存在,并与Integer… 兼容
Holger 2014年

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)撤消集合并对其进行.stream()处理,(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与其他流操作一起使用时,它并不是那么有用(collect join破坏了并行性)。在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开始,您可以使用的三个参数版本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 = {最后,中间,第一} =>第一,中间,最后

我开始collectingAndThencomonadStuart MarksArrayDeque收藏家那里使用中间收藏,尽管我对中间收藏不满意,然后再次流式传输

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

因此,我遍历了使用Collector.of工厂的Stuart Marks答案,该答案具有有趣的装订器 lambda。

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

ArrayDeque在堆栈中比Stack或LinkedList更快。“ push()”在双端队列的前面插入元素

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

可以根据定界符或空格修改split


1

最简单的解决方案是使用List::listIteratorStream::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 '19

0

这就是我的方法。

我不喜欢创建一个新集合并对其进行反向迭代的想法。

IntStream#map的想法很简洁,但我更喜欢IntStream#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

在所有这一切中,我没有看到我要首先回答的答案。

这并不是对问题的直接答案,但这是对该问题的潜在解决方案。

首先将列表向后构建。如果可以,请使用LinkedList而不是ArrayList,添加项目时请使用“推”而不是add。该列表将以相反的顺序构建,然后无需任何操作即可正确流式传输。

这不适用于您正在处理已以各种方式使用但在许多情况下都能正常工作的原始数组或列表的情况。


0

此方法适用于任何Stream,并且符合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以不同的方式使用。对于顺序排序,它纯粹是偶然的。我不建议任何人使用此解决方案。
塔吉尔·瓦列夫2015年

1
同样,当您进行设置时,它也不起作用System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
Tagir Valeev 2015年

我认为这只是按相反的顺序打印内容,而不是按排序的顺序(即降序),它也适用于并行流: public static <T> void reverseHelper(List<T> li){ li.parallelStream() .sorted((x,y)->-1) .collect(Collectors.toList()) .forEach(System.out::println); }
parmeshwor11 2015年

1
试试reverseHelper(IntStream.range(0, 8193).boxed().collect(Collectors.toList()))(结果可能取决于内核数)。
塔吉尔·瓦列夫2015年

-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 '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.