Java 8 流逆序 [英] Java 8 stream reverse order

查看:39
本文介绍了Java 8 流逆序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

General question: What's the proper way to reverse a stream? Assuming that we don't know what type of elements that stream consists of, what's the generic way to reverse any stream?

具体问题:

IntStream 提供 range 方法来生成特定范围内的整数 IntStream.range(-range, 0),现在我想将其从 0 转换为负数不起作用,我也不能使用 Integer::compare

IntStream provides range method to generate Integers in specific range IntStream.range(-range, 0), now that I want to reverse it switching range from 0 to negative won't work, also I can't use Integer::compare

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

使用 IntStream 我会得到这个编译器错误

with IntStream I'll get this compiler error

Error:(191, 0) ajc: IntStream 类型中的方法 sorted() 不适用于参数 (Integer::compare)

Error:(191, 0) ajc: The method sorted() in the type IntStream is not applicable for the arguments (Integer::compare)

我在这里遗漏了什么?

推荐答案

对于生成反向IntStream的具体问题,试试这样的:

For the specific question of generating a reverse IntStream, try something like this:

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

这避免了装箱和排序.

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

For the general question of how to reverse a stream of any type, I don't know of there's a "proper" way. There are a couple ways I can think of. Both end up storing the stream elements. I don't know of a way to reverse a stream without storing the elements.

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

This first way stores the elements into an array and reads them out to a stream in reverse order. Note that since we don't know the runtime type of the stream elements, we can't type the array properly, requiring an unchecked cast.

@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 对象的前面做了很多插入,所以有很多复制正在进行.

Another technique uses collectors to accumulate the items into a reversed list. This does lots of insertions at the front of ArrayList objects, so there's lots of copying going on.

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

可能可以使用某种自定义数据结构编写更高效的反向收集器.

It's probably possible to write a much more efficient reversing collector using some kind of customized data structure.

更新 2016-01-29

由于这个问题最近引起了一些关注,我想我应该更新我的答案以解决在 ArrayList 前面插入的问题.对于大量元素,这将是非常低效的,需要 O(N^2) 次复制.

Since this question has gotten a bit of attention recently, I figure I should update my answer to solve the problem with inserting at the front of ArrayList. This will be horribly inefficient with a large number of elements, requiring O(N^2) copying.

最好使用 ArrayDeque 代替,它有效地支持在前面插入.一个小问题是我们不能使用 Stream.collect() 的三参数形式;它需要将第二个 arg 的内容合并到第一个 arg 中,并且 Deque 上没有全部添加"批量操作.相反,我们使用 addAll() 将第一个 arg 的内容附加到第二个的末尾,然后返回第二个.这需要使用 Collector.of() 工厂方法.

It's preferable to use an ArrayDeque instead, which efficiently supports insertion at the front. A small wrinkle is that we can't use the three-arg form of Stream.collect(); it requires the contents of the second arg be merged into the first arg, and there's no "add-all-at-front" bulk operation on Deque. Instead, we use addAll() to append the contents of the first arg to the end of the second, and then we return the second. This requires using the Collector.of() factory method.

完整代码如下:

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

结果是一个 Deque 而不是 List,但这应该不是什么大问题,因为它现在可以很容易地迭代或流式传输-顺序颠倒.

The result is a Deque instead of a List, but that shouldn't be much of an issue, as it can easily be iterated or streamed in the now-reversed order.

这篇关于Java 8 流逆序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆