跳过流<T>中的最后一个 x 元素

2022-09-02 13:53:45

如果我有一个,我可以很容易地用来跳过流的前几个元素。但是,在流结束时跳过给定数量的元素似乎没有等效项。Stream<T>skip(long)

最明显的解决方案是 使用 ,但这需要事先知道初始长度,但情况并非总是如此。limit(originalLength - elementsToRemoveAtEnd)

有没有办法删除未知长度的流的最后几个元素,而不必将其收集到一个 ,计算元素并再次流式传输它?Collection


答案 1

对于长度未知的 s,没有通用的无存储解决方案。但是,您不需要收集整个流,只需要一个与要跳过的元素数量一样大的存储:Stream

static <T> Stream<T> skipLastElements(Stream<T> s, int count) {
    if(count<=0) {
      if(count==0) return s;
      throw new IllegalArgumentException(count+" < 0");
    }
    ArrayDeque<T> pending=new ArrayDeque<T>(count+1);
    Spliterator<T> src=s.spliterator();
    return StreamSupport.stream(new Spliterator<T>() {
        public boolean tryAdvance(Consumer<? super T> action) {
            while(pending.size()<=count && src.tryAdvance(pending::add));
            if(pending.size()>count) {
              action.accept(pending.remove());
              return true;
            }
          return false;
        }
        public Spliterator<T> trySplit() {
            return null;
        }
        public long estimateSize() {
            return src.estimateSize()-count;
        }
        public int characteristics() {
            return src.characteristics();
        }
    }, false);
}
public static void main(String[] args) {
    skipLastElements(Stream.of("foo", "bar", "baz", "hello", "world"), 2)
    .forEach(System.out::println);
}

答案 2

下面的代码用于缓冲元素,其中最后是要跳过的元素数。诀窍是使用。这会导致将第一批元素添加到 .然后,一旦元素被缓冲,流将继续处理元素,但从 中弹出元素。当到达流的末尾时,最后的元素将卡在 中并被丢弃。ArrayDequennskip(n)nArrayDequenArrayDequenArrayDeque

ArrayDeque不允许元素。下面的代码在添加到 之前映射到,然后在从 弹出后映射回来。nullnullNULL_VALUEArrayDequeNULL_VALUEnullArrayDeque

private static final Object NULL_VALUE = new Object();

public static <T> Stream<T> skipLast(Stream<T> input, int n)                   
{
   ArrayDeque<T> queue;

   if (n <= 0)
      return(input);

   queue = new ArrayDeque<>(n + 1);

   input = input.
      map(item -> item != null ? item : NULL_VALUE).
      peek(queue::add).
      skip(n).
      map(item -> queue.pop()).
      map(item -> item != NULL_VALUE ? item : null);

   return(input);
}

推荐