首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >从流中获取最后n个元素

从流中获取最后n个元素
EN

Stack Overflow用户
提问于 2015-05-27 15:42:54
回答 3查看 17.4K关注 0票数 37

我想知道有没有别的办法

代码语言:javascript
复制
List<X> lastN = all.subList(Math.max(0, all.size() - n), all.size());

使用?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-05-27 17:00:00

自定义收集器可以这样编写:

代码语言:javascript
复制
public static <T> Collector<T, ?, List<T>> lastN(int n) {
    return Collector.<T, Deque<T>, List<T>>of(ArrayDeque::new, (acc, t) -> {
        if(acc.size() == n)
            acc.pollFirst();
        acc.add(t);
    }, (acc1, acc2) -> {
        while(acc2.size() < n && !acc1.isEmpty()) {
            acc2.addFirst(acc1.pollLast());
        }
        return acc2;
    }, ArrayList::new);
}

并像这样使用它:

代码语言:javascript
复制
List<String> lastTen = input.stream().collect(lastN(10));
票数 26
EN

Stack Overflow用户

发布于 2015-05-27 16:58:39

如果流的大小未知,那么可能没有办法消耗整个流并缓冲到目前为止遇到的最后一个n元素。您可以使用某种类型的双端队列或专门的环形缓冲区自动保持其最大大小(有关某些实现,请参阅this related question )。

代码语言:javascript
复制
public static <T> List<T> lastN(Stream<T> stream, int n) {
    Deque<T> result = new ArrayDeque<>(n);
    stream.forEachOrdered(x -> {
        if (result.size() == n) {
            result.pop();
        }
        result.add(x);
    });
    return new ArrayList<>(result);
}

所有这些操作(sizepopadd)的复杂度都应该为O(1),因此长度为(未知)n的流的总体复杂度将为O(n)。

票数 4
EN

Stack Overflow用户

发布于 2019-08-08 17:57:19

有时我需要一个"oneliner“(在本例中是一个三行代码),因为创建一个收集器太麻烦了。

如果流很小,那么可以在不牺牲太多性能的情况下再次执行reverselimitreverse。这将产生最后n个元素。

如果需要过滤,则它很有用,因为在这种情况下,无法指定大小。

代码语言:javascript
复制
Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
  .filter(i -> i % 2 == 0)
  .sorted(Comparator.reverseOrder())
  .limit(2)
  .sorted(Comparator.naturalOrder())
  .forEach(System.out::println); // prints 6 8
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30476127

复制
相关文章

相似问题

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