首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Java 8流反向序

Java 8流反向序
EN

Stack Overflow用户
提问于 2014-06-03 08:09:45
回答 30查看 286.7K关注 0票数 212

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

具体问题:

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

代码语言:javascript
运行
复制
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)

我在这里错过了什么?

EN

回答 30

Stack Overflow用户

回答已采纳

发布于 2014-06-03 09:13:02

对于生成反向IntStream的具体问题,请尝试如下所示:

代码语言:javascript
运行
复制
static IntStream revRange(int from, int to) {
    return IntStream.range(from, to)
                    .map(i -> to - i + from - 1);
}

这避免了装箱和排序。

关于如何逆转任何类型的流的一般问题,我不知道有一种“适当”的方法。有几种方法我能想到。最后,两者都会存储流元素。我不知道有什么方法可以在不存储元素的情况下逆转流。

第一种方法是将元素存储到数组中,并以相反的顺序将它们读入流中。注意,由于我们不知道流元素的运行时类型,所以不能正确地键入数组,需要进行未检查的强制转换。

代码语言:javascript
运行
复制
@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对象的前面执行大量的插入操作,因此需要进行大量的复制。

代码语言:javascript
运行
复制
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的内容合并到第一个arg中,并且在Deque上没有“全前添加”的批量操作。相反,我们使用addAll()将第一个arg的内容附加到第二个arg的末尾,然后返回第二个arg。这需要使用Collector.of()工厂方法。

完整的代码如下:

代码语言:javascript
运行
复制
Deque<String> output =
    input.collect(Collector.of(
        ArrayDeque::new,
        (deq, t) -> deq.addFirst(t),
        (d1, d2) -> { d2.addAll(d1); return d2; }));

结果是一个Deque而不是一个List,但这不应该是什么问题,因为它可以很容易地按现在的顺序迭代或流。

票数 108
EN

Stack Overflow用户

发布于 2016-03-24 02:32:37

优雅的解决方案

代码语言:javascript
运行
复制
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream()
    .sorted(Collections.reverseOrder()) // Method on Stream<Integer>
    .forEach(System.out::println);
票数 68
EN

Stack Overflow用户

发布于 2014-06-12 11:40:58

一般性问题:

流不存储任何元素。

因此,如果不将元素存储在某个中间集合中,就不可能按反向顺序迭代元素。

代码语言:javascript
运行
复制
Stream.of("1", "2", "20", "3")
      .collect(Collectors.toCollection(ArrayDeque::new)) // or LinkedList
      .descendingIterator()
      .forEachRemaining(System.out::println);

更新:将LinkedList更改为ArrayDeque (更好) see here for details

指纹:

代码语言:javascript
运行
复制
3

20

2

1

顺便说一句,使用sort方法是不正确的,因为它排序,而不是反转(假设流可能有无序元素)

具体问题:

我发现这个简单,简单,直观(复制@Holger comment)

代码语言:javascript
运行
复制
IntStream.iterate(to - 1, i -> i - 1).limit(to - from)
票数 53
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24010109

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档