@Override default Stream<T> drop(int n) { Stream<T> stream = this; while (n-- > 0 && !stream.isEmpty()) { stream = stream.tail(); } return stream; }
@Override default Stream<T> sorted(Comparator<? super T> comparator) { Objects.requireNonNull(comparator, "comparator is null"); return isEmpty() ? this : toJavaStream().sorted(comparator).collect(Stream.collector()); }
@Override default Stream<T> dropWhile(Predicate<? super T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); Stream<T> stream = this; while (!stream.isEmpty() && predicate.test(stream.head())) { stream = stream.tail(); } return stream; }
@Override default int indexOf(T element, int from) { int index = 0; for (Stream<T> stream = this; !stream.isEmpty(); stream = stream.tail(), index++) { if (index >= from && Objects.equals(stream.head(), element)) { return index; } } return -1; }
@Override default int lastIndexOf(T element, int end) { int result = -1, index = 0; for (Stream<T> stream = this; index <= end && !stream.isEmpty(); stream = stream.tail(), index++) { if (Objects.equals(stream.head(), element)) { result = index; } } return result; }
@Override protected T getNext() { if (stream.isEmpty()) { stream = Stream.iterate(nextFunction.apply(last), nextFunction); } last = stream.head(); stream = stream.tail(); return last; }
@Override default Stream<T> peek(Consumer<? super T> action) { Objects.requireNonNull(action, "action is null"); if (isEmpty()) { return this; } else { final T head = head(); action.accept(head); return cons(head, () -> tail().peek(action)); } }
@Override default Stream<T> takeRight(int n) { Stream<T> right = this; Stream<T> remaining = drop(n); while (!remaining.isEmpty()) { right = right.tail(); remaining = remaining.tail(); } return right; }
@Override default <U> Stream<U> map(Function<? super T, ? extends U> mapper) { Objects.requireNonNull(mapper, "mapper is null"); if (isEmpty()) { return Empty.instance(); } else { return cons(mapper.apply(head()), () -> tail().map(mapper)); } }
@Override default Stream<T> removeAt(int index) { if (index < 0) { throw new IndexOutOfBoundsException("removeAt(" + index + ")"); } else if (index == 0) { return tail(); } else if (isEmpty()) { throw new IndexOutOfBoundsException("removeAt() on Nil"); } else { return cons(head(), () -> tail().removeAt(index - 1)); } }
@Override default Stream<T> replaceAll(T currentElement, T newElement) { if (isEmpty()) { return this; } else { final T head = head(); final T newHead = Objects.equals(head, currentElement) ? newElement : head; return cons(newHead, () -> tail().replaceAll(currentElement, newElement)); } }
private Cons<T> appendAll(Cons<T> stream, Function<? super Stream<T>, ? extends Stream<T>> mapper) { return (Cons<T>) Stream.cons(stream.head(), () -> { final Stream<T> tail = stream.tail(); return tail.isEmpty() ? mapper.apply(self) : appendAll((Cons<T>) tail, mapper); }); }
@Override default Stream<T> appendAll(Iterable<? extends T> elements) { Objects.requireNonNull(elements, "elements is null"); if (Collections.isEmpty(elements)) { return this; } else if (isEmpty()) { return Stream.ofAll(elements); } else { return Stream.ofAll(Iterator.concat(this, elements)); } }
@Override default Stream<T> insert(int index, T element) { if (index < 0) { throw new IndexOutOfBoundsException("insert(" + index + ", e)"); } else if (index == 0) { return cons(element, () -> this); } else if (isEmpty()) { throw new IndexOutOfBoundsException("insert(" + index + ", e) on Nil"); } else { return cons(head(), () -> tail().insert(index - 1, element)); } }
@Override default Stream<T> removeFirst(Predicate<T> predicate) { Objects.requireNonNull(predicate, "predicate is null"); if (isEmpty()) { return this; } else { final T head = head(); return predicate.test(head) ? tail() : cons(head, () -> tail().removeFirst(predicate)); } }
@Override default Stream<T> remove(T element) { if (isEmpty()) { return this; } else { final T head = head(); return Objects.equals(head, element) ? tail() : cons(head, () -> tail().remove(element)); } }
@Override default Stream<T> replace(T currentElement, T newElement) { if (isEmpty()) { return this; } else { final T head = head(); if (Objects.equals(head, currentElement)) { return cons(newElement, this::tail); } else { return cons(head, () -> tail().replace(currentElement, newElement)); } } }
@Override default Tuple2<Stream<T>, Stream<T>> splitAtInclusive(Predicate<? super T> predicate) { final Tuple2<Stream<T>, Stream<T>> split = splitAt(predicate); if (split._2.isEmpty()) { return split; } else { return Tuple.of(split._1.append(split._2.head()), split._2.tail()); } }
@Override default Stream<T> take(int n) { if (n < 1 || isEmpty()) { return empty(); } else if (n == 1) { return cons(head(), Stream::empty); } else { return cons(head(), () -> tail().take(n - 1)); } }
static <T> Stream<T> apply(io.vavr.collection.List<T> front, io.vavr.collection.List<T> rear, Stream<T> remaining) { if (remaining.isEmpty()) { return remaining; } else if (front.isEmpty()) { return apply(rear.reverse(), io.vavr.collection.List.empty(), remaining); } else { return Stream.cons(front.head(), () -> apply(front.tail(), rear.prepend(remaining.head()), remaining.tail())); } } }