返回Java Streams中的N个最后元素

时间:2016-10-19 15:40:50

标签: java string split java-8 java-stream

这个问题只是为了好玩。

我有这个方法:

private static String getBaseDomain(String fullDomain) {
    // we take the base domain from the usual xxx.yyy.basedomain.tld: we 
    // want only the last 2 elements: basedomain.tld
    List<String> elements = Arrays.asList(fullDomain.split("\\."));
    if( elements.size() > 2){
        elements = elements.subList(elements.size()-2, elements.size());
    }
    return String.join(".", elements);
}

我想知道如何使用java流API获得相同的结果(实际上,我想知道哪种方法最节省资源)。

我无法计算如何仅从流中获取最后2个元素:limit(2)将为我提供第一个两个,而对于skip(XXX),我不会#39;知道如何提取流的大小&#34;内联&#34;。

你能告诉我你会怎么做吗?

4 个答案:

答案 0 :(得分:5)

您可以使用skip

elements.stream().skip(elements.size() - 2)

来自API

  

在丢弃流的前n个元素后,返回由此流的其余元素组成的流。如果此流包含少于n个元素,则将返回空流。

可能没用的例子

// a list made of a, b, c and d
List<String> l = Arrays.asList("a", "b", "c", "d");

// prints c and d
l.stream().skip(l.size() - 2).forEach(System.out::println);

可能无用的说明

正如少数人所提到的,只有当你有一个可以使用的尺寸时,这才有效,即如果你从一个集合中流式传输。

引用Nicolas,流没有大小。

答案 1 :(得分:2)

您可以对原始方法进行一些内联​​,我认为它可以很好地缩短它,您甚至不必使用流:

    String[] a = fullDomain.split("\\.");
    return String.join(".", Arrays.asList(a)
                                  .subList(Math.max(0, a.length-2), a.length));

如果您真的想使用流,可以使用数组子范围流源:

    String[] a = fullDomain.split("\\.");
    return Arrays.stream(a, Math.max(0, a.length-2), a.length)
                 .collect(Collectors.joining("."));

如果你所拥有的只是一个你没有预先确定其大小的流,我只是将这些元素转储到ArrayDeque

    final int N = 2;
    Stream<String> str = ... ;

    Deque<String> deque = new ArrayDeque<>(N);
    str.forEachOrdered(s -> {
        if (deque.size() == N) deque.removeFirst();
        deque.addLast(s);
    });
    return String.join(".", deque);

当然,这不像写一个收藏家那​​么笼统,但对于简单的情况,它可能就好了。

答案 2 :(得分:1)

如果elements是一个流,您可以编写一个自定义收集器来保留最后K个元素(可能还有这样的收集器):

List<?> lastK = ints.stream().collect(
    Collector.of(
        LinkedList::new,
        (listA, el) -> {
            listA.add(el);
            if (listA.size() > K) {
              listA.remove(0);
            }
        },
        (listA, listB) -> {
            while (listB.size() < K && !listA.isEmpty()) {
              listB.addFirst(listA.removeLast());
            }
            return listB;
        }));

答案 3 :(得分:1)

如果是索引集合,您可以使用

IntStream.range(elements.size() - 2, elements.size()).mapToObj(elements::get).forEach(System.out::print);