Java 8 流倒序

新手上路,请多包涵

一般问题:反转流的正确方法是什么?假设我们不知道流由什么类型的元素组成,那么反转任何流的通用方法是什么?

具体问题:

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 )

我在这里错过了什么?

原文由 vach 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 956
2 个回答

对于生成反向 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 代替,它有效地支持在前面插入。一个小问题是我们不能使用 Stream.collect() 的三参数形式;它要求将第二个 arg 的内容合并到第一个 arg 中,并且在 Deque 上没有“add-all-at-front”批量操作。相反,我们使用 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; }));

结果是 Deque 而不是 List ,但这应该不是什么大问题,因为它可以很容易地以现在相反的顺序迭代或流式传输。

原文由 Stuart Marks 发布,翻译遵循 CC BY-SA 3.0 许可协议

优雅的解决方案

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

原文由 Kishan B 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏