All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jena.atlas.iterator.Iter Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.atlas.iterator;

import java.io.PrintStream;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.apache.jena.atlas.io.IO;
import org.apache.jena.atlas.lib.Closeable;
import org.apache.jena.atlas.lib.Sink;

/**
 * Iter provides general utilities for working with {@linkplain Iterator Iterators}.
 * This class provides functionality similar to {@code Stream}
 * except for iterators (and hence single threaded).
 * 

* Style 1: functional style using statics. * *

 *  import static org.apache.jena.atlas.iterator.Iter.*;
 *
 *  filter(map(iterator, function), predicate)
 * 
* * Style 2: Stream-like: The class {@code Iter} provides methods to call on an iterator. * *
 * import static org.apache.jena.atlas.iterator.Iter.iter;
 *
 * iter(iterator).map(...).filter(...)
 * 
* * The operations attempt to close iterators - see {@link Iter#close(Iterator)}. * Caution - not all Iterators in this package provide close or passdown close operations * {@link IteratorOnClose} adds a {@link Runnable} action called once on close. *

* Iterators do not guarantee {@code .remove}. * * @param the type of element over which an instance of {@code Iter} iterates, */ public class Iter implements IteratorCloseable { /** Shorter form of "forEachRemaining" */ public static void forEach(Iterator iter, Consumer action) { iter.forEachRemaining(action); } public static Stream asStream(Iterator iterator) { return asStream(iterator, false); } public static Stream asStream(Iterator iterator, boolean parallel) { int characteristics = Spliterator.IMMUTABLE; Stream stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, characteristics), parallel); stream.onClose(()->close(iterator)); return stream; } // ---- Special iterators. public static Iterator singleton(T item) { // There is a singleton iterator in Collections but it is not public. return new SingletonIterator<>(item); } public static Iterator nullIterator() { return Collections.emptyIterator(); } // -- Stream inspired names public static Iter empty() { return Iter.iter(Collections.emptyIterator()); } public static Iter of(T item) { return Iter.iter(new SingletonIterator<>(item)); } @SafeVarargs public static Iter of(T ...items) { return Iter.iter(List.of(items).iterator()); } public static Iter ofNullable(T t) { return t == null ? Iter.empty() : Iter.of(t); } /** * Return an iterator that does not permit remove. * This makes an "UnmodifiableIterator". */ public static Iterator noRemove(Iterator iter) { return new IteratorWrapper(iter) { @Override public final void remove() { throw new UnsupportedOperationException("remove"); } }; } // ---- Collectors. /** Collect an iterator into a set. */ public static Set toSet(Iterator stream) { return collect(stream, Collectors.toSet()); } /** Collect an iterator into a list. */ public static List toList(Iterator stream) { return collect(stream, Collectors.toList()); } /** * Create another iterator without risk of concurrent modification * exceptions. This materializes the input iterator. */ public static Iterator iterator(Iterator iterator) { List x = Iter.toList(iterator); return x.iterator(); } // Note fold-left and fold-right // http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29 // This reduce is a kind of fold-left (take first element, apply to rest of list) // and can deal with lists of zero elements. // -- Operations on iterators. @FunctionalInterface public interface Folder extends BiFunction {} public static R foldLeft(Iterator stream, R value, Folder function) { // Tail recursion, unwound for (; stream.hasNext();) { T item = stream.next(); value = function.apply(value, item); } return value; } public static R foldRight(Iterator stream, R value, Folder function) { // Recursive. if ( !stream.hasNext() ) return value; T item = stream.next(); return function.apply(foldRight(stream, value, function), item); } public static Optional reduce(Iterator iter, BinaryOperator accumulator) { T r = reduce(iter, null, accumulator); return Optional.ofNullable(r); } public static T reduce(Iterator iter, T identity, BinaryOperator accumulator) { T result = identity; while(iter.hasNext()) { T elt = iter.next(); result = (result == null) ? elt : accumulator.apply(result, elt); } return result; } // ---- min and max public static Optional min(Iterator iter, Comparator comparator) { T x = null; while(iter.hasNext()) { T elt = iter.next(); if ( x == null ) x = elt; else { int cmp = comparator.compare(x, elt); if ( cmp > 0 ) x = elt; } } return Optional.ofNullable(x); } public static Optional max(Iterator iter, Comparator comparator) { // Or min(iter, comparator.reversed()) T x = null; while(iter.hasNext()) { T elt = iter.next(); if ( x == null ) x = elt; else { int cmp = comparator.compare(x, elt); if ( cmp < 0 ) x = elt; } } return Optional.ofNullable(x); } // ---- collect /** See {@link Stream#collect(Supplier, BiConsumer, BiConsumer)}, except without the {@code BiConsumer combiner} */ public static R collect(Iterator iter, Supplier supplier, BiConsumer accumulator) { R result = supplier.get(); iter.forEachRemaining(elt -> accumulator.accept(result, elt)); return result; } /** See {@link Stream#collect(Collector)} */ public static R collect(Iterator iter, Collector collector) { A a = collect(iter, collector.supplier(), collector.accumulator()); return collector.finisher().apply(a); } /** Act on elements of an iterator. * @see #map(Iterator, Function) */ public static void apply(Iterator stream, Consumer action) { stream.forEachRemaining(action); } // ---- Filter public static Iterator filter(final Iterator stream, final Predicate filter) { return new IterFiltered(stream, filter); } public static Iterator notFilter(final Iterator stream, final Predicate filter) { return filter(stream, filter.negate()); } // Filter-related private static final class IterFiltered implements IteratorCloseable { private final Iterator stream; private final Predicate filter; private boolean finished = false; private boolean slotOccupied = false; private T slot; private IterFiltered(Iterator stream, Predicate filter) { this.stream = stream; this.filter = filter; } @Override public boolean hasNext() { if ( finished ) return false; while (!slotOccupied) { if ( !stream.hasNext() ) { closeIterator(); break; } T nextItem = stream.next(); if ( filter.test(nextItem) ) { slot = nextItem; slotOccupied = true; break; } } return slotOccupied; } @Override public T next() { if ( hasNext() ) { slotOccupied = false; return slot; } closeIterator(); throw new NoSuchElementException("filter.next"); } @Override public void forEachRemaining(Consumer action) { if ( finished ) return; if ( slotOccupied ) { action.accept(slot); } T t; while (stream.hasNext()) { t = stream.next(); if ( filter.test(t) ) action.accept(t); } slotOccupied = false; } private void closeIterator() { if ( finished ) return; finished = true; Iter.close(stream); } @Override public void close() { closeIterator(); } } /** * Return true if every element of stream passes the filter (reads the * stream until the first element not passing the filter) */ public static boolean allMatch(Iterator iter, Predicate predicate) { try { while (iter.hasNext()) { T item = iter.next(); if ( !predicate.test(item) ) { Iter.close(iter); return false; } } return true; } finally { Iter.close(iter); } } /** * Return true if one or more elements of stream passes the filter (reads the * stream to first element passing the filter) */ public static boolean anyMatch(Iterator iter, Predicate predicate) { try { while (iter.hasNext()) { T item = iter.next(); if ( predicate.test(item) ) { Iter.close(iter); return true; } } return false; } finally { Iter.close(iter); } } /** * Return true if none of the elements of the iterator passes the predicate test reads * the stream to first element passing the filter) */ public static boolean noneMatch(Iterator iter, Predicate predicate) { return ! anyMatch(iter, predicate); } /** * Return an Optional with the first element of an iterator that matches the predicate. * Return {@code Optional.empty} if none match. * Reads the iterator until the first match. */ public static Optional findFirst(Iterator iter, Predicate predicate) { while ( iter.hasNext() ) { T item = iter.next(); if ( predicate.test(item) ) return Optional.of(item); } return Optional.empty(); } /** * Return an Optional with the last element of an iterator that matches the predicate. * Return {@code Optional.empty} if no match. * Reads the iterator to completion. */ public static Optional findLast(Iterator iter, Predicate predicate) { T thing = null; while ( iter.hasNext() ) { T item = iter.next(); if ( predicate.test(item) ) thing = item; } return Optional.ofNullable(thing); } /** * Return an Optional with an element of an iterator that matches the predicate. * Return {@code Optional.empty} if none match. * The element returned is not specified by the API contract. */ public static Optional findAny(Iterator iter, Predicate predicate) { return findFirst(iter, predicate); } // ---- Map /** * Apply a function to every element of an iterator, transforming it * from a {@code T} to an {@code R}. */ public static Iterator map(Iterator stream, Function converter) { return new IterMap<>(stream, converter); } private static final class IterMap implements IteratorCloseable { private final Iterator stream; private final Function converter; private IterMap(Iterator stream, Function converter) { this.stream = stream; this.converter = converter; } @Override public boolean hasNext() { return stream.hasNext(); } @Override public R next() { return converter.apply(stream.next()); } @Override public void forEachRemaining(Consumer action) { stream.forEachRemaining(item->action.accept(converter.apply(item))); } @Override public void close() { Iter.close(stream); } } /** * Apply a function to every element of an iterator, to produce possibly multiple mapping each time. * See {@link Stream#flatMap} */ public static Iterator flatMap(Iterator iter, Function> mapper) { return new IteratorFlatMap<>(iter, mapper); } /** * Apply an action to everything in stream, yielding a stream of the * same items. */ public static Iterator operate(final Iterator stream, final Consumer action) { final Iterator iter = new IterOperate(stream, action); return iter; } private static final class IterOperate implements IteratorCloseable { private final Iterator stream; private final Consumer action; private IterOperate(Iterator stream, Consumer action) { this.stream = stream; this.action = action; } @Override public boolean hasNext() { return stream.hasNext(); } @Override public T next() { T t = stream.next(); action.accept(t); return t; } @Override public void forEachRemaining(Consumer action) { stream.forEachRemaining(item->{ this.action.accept(item); action.accept(item); }); } @Override public void close() { Iter.close(stream); } } /** Print an iterator as it gets used - this adds a printing wrapper */ public static Iterator printWrapper(final Iterator stream) { return Iter.printWrapper(System.out, stream); } /** Print an iterator as it gets used - this adds a printing wrapper */ public static Iterator printWrapper(final PrintStream out, final Iterator stream) { return Iter.operate(stream, out::println); } /** Join two iterators. * If there, potentially, going to be many iterators, it is better to * create an {@link IteratorConcat} explicitly and add each iterator. */ public static Iterator append(Iterator iter1, Iterator iter2) { return IteratorCons.create(iter1, iter2); } /** Return an iterator that will see each element of the underlying iterator only once. * Note that this need working memory to remember the elements already seen. */ public static Iterator distinct(Iterator iter) { return filter(iter, new FilterUnique()); } /** Remove adjacent duplicates. This operation does not need * working memory to remember the all elements already seen, * just a slot for the last element seen. */ public static Iterator distinctAdjacent(Iterator iter) { return filter(iter, new FilterDistinctAdjacent()); } /** Remove nulls from an iterator */ public static Iterator removeNulls(Iterator iter) { return filter(iter, Objects::nonNull); } /** Step forward up to {@code steps} places. *
Return number of steps taken. * * @apiNote * The iterator is moved at most {@code steps} places with no overshoot. * The iterator can be used afterwards. */ public static int step(Iterator iter, int steps) { for ( int i = 0; i < steps; i++) { if ( ! iter.hasNext() ) return i; iter.next(); } return steps; } /** Take the first N elements of an iterator - stop early if too few * @see #limit(Iterator, long) */ public static List take(Iterator iter, int N) { iter = new IterLimit<>(iter, N); List x = new ArrayList<>(N); while ( iter.hasNext() ) x.add(iter.next()); return x; } /** Create an iterator such that it yields elements while a predicate test on * the elements is true, end the iteration. * @see Iter#filter(Iterator, Predicate) */ public static Iterator takeWhile(Iterator iter, Predicate predicate) { return new IteratorTruncate<>(iter, predicate); } /** * Create an iterator such that it yields elements until a predicate test on * the elements becomes true, end the iteration. * * @see Iter#filter(Iterator, Predicate) */ public static Iterator takeUntil(Iterator iter, Predicate predicate) { return new IteratorTruncate<>(iter, predicate.negate()); } /** Create an iterator such that elements from the front while * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicted becomes true is the first element of the * returned iterator. */ public static Iterator dropWhile(Iterator iter, Predicate predicate) { PeekIterator iter2 = new PeekIterator<>(iter); for(;;) { T elt = iter2.peek(); if ( elt == null ) return Iter.nullIterator(); if ( ! predicate.test(elt) ) break; } return iter2; } /** Create an iterator such that elements from the front until * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicate becomes true is the first element of the * returned iterator. */ public static Iterator dropUntil(Iterator iter, Predicate predicate) { return dropWhile(iter, predicate.negate()); } /** Return an iterator that is limited to the given number of elements. * If it is shorter than the limit, stop at the end. * @see #take(Iterator, int) */ public static Iterator limit(Iterator iterator, long limit) { return new IterLimit<>(iterator, limit); } private static class IterLimit implements IteratorCloseable { private long count = 0; private final long limit; private boolean closed = false; private final Iterator iterator; private IterLimit(Iterator stream, long limit) { this.iterator = stream; this.limit = limit; } @Override public boolean hasNext() { if ( count >= limit ) { closeOnce(); return false; } boolean b = iterator.hasNext(); if ( !b ) closeOnce(); return b; } @Override public T next() { try { T t = iterator.next(); count++; return t; } catch (NoSuchElementException ex) { closeOnce(); throw ex; } } private void closeOnce() { if ( ! closed ) Iter.close(iterator); closed = true; } @Override public void close() { closeOnce(); } @Override public void remove() { // But leave the count as-is. iterator.remove(); } } /** Skip over a number of elements of an iterator */ public static Iterator skip(Iterator iterator, long limit) { for ( long i = 0; i < limit; i++ ) { if ( iterator.hasNext() ) iterator.next(); else // Now exhausted. break; } return iterator; } /** Count the iterator (this is destructive on the iterator) */ public static long count(Iterator iterator) { ActionCount action = new ActionCount<>(); iterator.forEachRemaining(action); return action.getCount(); } /** Consume the iterator */ public static void consume(Iterator iterator) { iterator.forEachRemaining(x->{}); // Do nothing. } /** Create a string from an iterator, using the separator. Note: this consumes the iterator. */ public static String asString(Iterator stream, String sep) { return Iter.iter(stream).map(x->x.toString()).collect(Collectors.joining(sep)); } /** Create a string from an iterator, using the separator, prefix and suffix. Note: this consumes the iterator. */ public static String asString(Iterator stream, CharSequence sep, CharSequence prefix, CharSequence suffix) { return Iter.iter(stream).map(x->x.toString()).collect(Collectors.joining(sep, prefix, suffix)); } /** Close iterator if marked with {@link Closeable}. */ public static void close(Iterator iter) { if ( iter instanceof Closeable cIter ) cIter.close(); } /** * Run an action when an iterator is closed. This assumes the iterator closed * with {@link Iter#close}. *

* Convenience function for closing a {@link java.io.Closeable} after use when * passing an iterator out of scope. */ public static IteratorCloseable onCloseIO(Iterator iterator, java.io.Closeable ioThing) { return onClose(iterator, ()->IO.close(ioThing)); } /** * Run an action when an iterator is closed. * This assumes the iterator closed with {@link Iter#close}. */ public static IteratorOnClose onClose(Iterator iter, Runnable closeHandler) { return IteratorOnClose.atEnd(iter, closeHandler); } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs now. See {@link #debug} for an operation to print as the * iterator is used. */ public static Iterator log(Iterator stream) { return log(System.out, stream); } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs now. See {@link #debug} for an operation to print as the * iterator is used. */ public static Iterator log(final PrintStream out, Iterator stream) { Iterator iter = debug(out, stream); // And force it to run. if ( ! iter.hasNext() ) out.println(""); return Iter.toList(iter).iterator(); } /** * Print an iterator to stdout, return a copy of the iterator. Printing * occurs when the iterator is used. See {@link #log} for * an operation to print now. */ public static Iterator debug(Iterator stream) { return debug(System.out, stream); } /** * Print an iterator, return a copy of the iterator. Printing * occurs as the returned iterator is used. */ public static Iterator debug(final PrintStream out, Iterator stream) { try { return map(stream, item -> {out.println(item); return item;}); } finally { out.flush(); } } /** Print an iterator (destructive) */ public static void print(Iterator stream) { print(System.out, stream); } /** Print an iterator (destructive) */ public static void print(PrintStream out, Iterator stream) { stream.forEachRemaining(out::println); } /** Send the elements of the iterator to a sink - consumes the iterator */ public static void sendToSink(Iterator iter, Sink sink) { iter.forEachRemaining(sink::send); sink.close(); } // ---- // Iter class part : factories public static Iter iter(Iter iter) { return iter; } public static Iter iter(Collection collection) { return iter(collection.iterator()); } public static Iter iter(Iterator iterator) { Objects.requireNonNull(iterator); if ( iterator instanceof Iter iter ) return iter; return new Iter<>(iterator); } public static Iter singletonIter(T item) { return iter(new SingletonIterator<>(item)); } public static Iter nullIter() { return iter(new NullIterator()); } /** * Materialize an iterator, that is, force it to run now - useful in * debugging or when iteration may modify underlying datastructures. */ public static Iterator materialize(Iterator iter) { return toList(iter).iterator(); } /** An {@code Iter} of 2 {@code Iter}'s */ public static Iter concat(Iter iter1, Iter iter2) { if ( iter1 == null ) return iter2; if ( iter2 == null ) return iter1; return iter1.append(iter2); } /** An {@code Iterator} of 2 {@code Iterator}'s. * See also {@link IteratorConcat}. */ public static Iter concat(Iterator iter1, Iterator iter2) { if ( iter1 == null ) return iter(iter2); if ( iter2 == null ) return iter(iter1); return iter(iter1).append(iter(iter2)); } /** Return the first element of an iterator or null if no such element. * @param iter * @return An item or null. */ public static T first(Iterator iter) { return first(iter, (x)-> true ); } /** Skip to the first element meeting a condition and return that element. */ public static T first(Iterator iter, Predicate filter) { while (iter.hasNext()) { T t = iter.next(); if ( filter.test(t) ) return t; } return null; } /** Skip to the first element meeting a condition and return that element's index (zero-based). */ public static int firstIndex(Iterator iter, Predicate filter) { for (int idx = 0; iter.hasNext(); idx++) { T t = iter.next(); if ( filter.test(t) ) return idx; } return -1; } /** Return the last element or null, if no elements. This operation consumes the iterator. */ public static T last(Iterator iter) { return last(iter, (x)->true); } /** Return the last element satisfying a predicate. This operation consumes the whole iterator. */ public static T last(Iterator iter, Predicate filter) { T thing = null; while (iter.hasNext()) { T t = iter.next(); if ( filter.test(t) ) thing = t; } return thing; } /** Find the last occurrence, defined by a predicate, in a list. */ public static int lastIndex(List list, Predicate filter) { for (int idx = list.size()-1; idx >= 0; idx--) { T t = list.get(idx); if ( filter.test(t) ) return idx; } return -1; } /** reverse iterator for a list */ public static Iterator reverseIterate(List list) { ListIterator iter = list.listIterator(list.size()); return new Iterator<>() { @Override public boolean hasNext() { return iter.hasPrevious(); } @Override public T next() { return iter.previous(); } }; } /** reverse for each on a list. */ public static void reverseIterate(List list, Consumer action) { ListIterator iter = list.listIterator(list.size()); while(iter.hasPrevious()) { T t = iter.previous(); action.accept(t); } } // ------------------------------------------------------ // The class. private Iterator iterator; private Iter(Iterator iterator) { this.iterator = iterator; } @Override public void close() { Iter.close(iterator); } /** Apply the Consumer to each element of the iterator */ public void forEach(Consumer action) { iterator.forEachRemaining(action); } @Override public void forEachRemaining(Consumer action) { iterator.forEachRemaining(action); } /** Consume the {@code Iter} and produce a {@code Set} */ public Set toSet() { return toSet(iterator); } /** Consume the {@code Iter} and produce a {@code List} */ public List toList() { return toList(iterator); } public void sendToSink(Sink sink) { sendToSink(iterator, sink); } public T first() { return first(iterator); } public T last() { return last(iterator); } /** Skip to the first element meeting a condition and return that element. */ public T first(Predicate filter) { return first(iterator, filter); } /** Skip to the first element meeting a condition and return that element's index (zero-based). */ public int firstIndex(Predicate filter) { return firstIndex(iterator, filter); } /** Filter by predicate */ public Iter filter(Predicate filter) { return iter(filter(iterator, filter)); } public boolean allMatch(Predicate predicate) { return allMatch(iterator, predicate); } public boolean anyMatch(Predicate predicate) { return anyMatch(iterator, predicate); } public boolean noneMatch(Predicate predicate) { return noneMatch(iterator, predicate); } public Optional findFirst(Predicate predicate) { return findFirst(iterator, predicate); } public Optional findAny(Predicate predicate) { return findAny(iterator, predicate); } public Optional findLast(Predicate predicate) { return findLast(iterator, predicate); } /** Remove nulls */ public Iter removeNulls() { return iter(removeNulls(this)); } /** Map each element using given function */ public Iter map(Function converter) { return iter(map(iterator, converter)); } /** FlatMap each element using given function of element to iterator of mapped elements.s */ public Iter flatMap(Function> converter) { return iter(flatMap(iterator, converter)); } /** * Apply an action to everything in the stream, yielding a stream of the * original items. */ public Iter operate(Consumer action) { return iter(operate(iterator, action)); } public R foldLeft(R initial, Folder accumulator) { return foldLeft(iterator, initial, accumulator); } public R foldRight(R initial, Folder accumulator) { return foldRight(iterator, initial, accumulator); } /** Reduce. * This reduce is fold-left (take first element, apply to rest of list) */ public Optional reduce(BinaryOperator accumulator) { return reduce(iterator, accumulator); } public T reduce(T identity, BinaryOperator accumulator) { return reduce(iterator, identity, accumulator); } public Optional min(Comparator comparator) { return min(iterator, comparator); } public Optional max(Comparator comparator) { return max(iterator, comparator); } /** See {@link Stream#collect(Supplier, BiConsumer, BiConsumer)}, except without the {@code BiConsumer combiner} */ public R collect(Supplier supplier, BiConsumer accumulator/*, BiConsumer combiner*/) { return collect(iterator, supplier, accumulator); } /** See {@link Stream#collect(Collector)} */ public R collect(Collector collector) { return collect(iterator, collector); } /** Apply an action to every element of an iterator */ public void apply(Consumer action) { iterator.forEachRemaining(action); } /** Join on an {@code Iterator}.. * If there are going to be many iterators, it is better to create an {@link IteratorConcat} * and {@code .add} each iterator. The overheads are much lower. */ public Iter append(Iterator iter) { return iter(IteratorCons.create(iterator, iter)); } /** Return an Iter that yields at most the first N items */ public Iter take(int N) { return iter(take(iterator, N)); } /** Create an {@code Iter} such that it yields elements while a predicate test on * the elements is true, end the iteration. * @see Iter#filter(Predicate) */ public Iter takeWhile(Predicate predicate) { return iter(takeWhile(iterator, predicate)); } /** * Create an {@code Iter} such that it yields elements until a predicate test on * the elements becomes true, end the iteration. * * @see Iter#filter(Predicate) */ public Iter takeUntil(Predicate predicate) { return iter(takeUntil(iterator, predicate)); } /** Create an {@code Iter} such that elements from the front while * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicted becomes true is the first element of the * returned iterator. */ public Iter dropWhile(Predicate predicate) { return iter(dropWhile(iterator, predicate)); } /** Create an {@code Iter} such that elements from the front until * a predicate test become true are dropped then return all remaining elements * are iterated over. * The first element where the predicate becomes true is the first element of the * returned iterator. */ public Iter dropUntil(Predicate predicate) { return iter(dropWhile(iterator, predicate.negate())); } /** Limit the number of elements. */ public Iter limit(long N) { return Iter.iter(limit(null, N)); } /** Skip over a number of elements. */ public Iter skip(long N) { return Iter.iter(skip(null, N)); } /** Count the iterator (this is destructive on the iterator) */ public long count() { ActionCount action = new ActionCount<>(); this.forEachRemaining(action); return action.getCount(); } /** * Return an {@code Iter} that will see each element of the underlying iterator only once. * Note that this need working memory to remember the elements already seen. */ public Iter distinct() { return iter((distinct(iterator))); } /** Remove adjacent duplicates. This operation does not need * working memory to remember the all elements already seen, * just a slot for the last element seen. */ public Iter distinctAdjacent() { return iter(distinctAdjacent(iterator)); } // ---- Iterator @Override public boolean hasNext() { return iterator.hasNext(); } @Override public T next() { return iterator.next(); } @Override public void remove() { iterator.remove(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy