com.google.common.collect.Iterables Maven / Gradle / Ivy
/*
* Copyright (C) 2007 The Guava Authors
*
* Licensed 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 com.google.common.collect;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkRemove;
import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.RandomAccess;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* An assortment of mainly legacy static utility methods that operate on or return objects of type
* {@code Iterable}. Except as noted, each method has a corresponding {@link Iterator}-based method
* in the {@link Iterators} class.
*
* Java 8 users: several common uses for this class are now more comprehensively addressed
* by the new {@link java.util.stream.Stream} library. Read the method documentation below for
* comparisons. This class is not being deprecated, but we gently encourage you to migrate to
* streams.
*
*
Performance notes: Unless otherwise noted, all of the iterables produced in this class
* are lazy, which means that their iterators only advance the backing iteration when
* absolutely necessary.
*
*
See the Guava User Guide article on {@code
* Iterables}.
*
* @author Kevin Bourrillion
* @author Jared Levy
* @since 2.0
*/
@GwtCompatible(emulated = true)
public final class Iterables {
private Iterables() {}
/** Returns an unmodifiable view of {@code iterable}. */
public static Iterable unmodifiableIterable(final Iterable extends T> iterable) {
checkNotNull(iterable);
if (iterable instanceof UnmodifiableIterable || iterable instanceof ImmutableCollection) {
@SuppressWarnings("unchecked") // Since it's unmodifiable, the covariant cast is safe
Iterable result = (Iterable) iterable;
return result;
}
return new UnmodifiableIterable<>(iterable);
}
/**
* Simply returns its argument.
*
* @deprecated no need to use this
* @since 10.0
*/
@Deprecated
public static Iterable unmodifiableIterable(ImmutableCollection iterable) {
return checkNotNull(iterable);
}
private static final class UnmodifiableIterable extends FluentIterable {
private final Iterable extends T> iterable;
private UnmodifiableIterable(Iterable extends T> iterable) {
this.iterable = iterable;
}
@Override
public Iterator iterator() {
return Iterators.unmodifiableIterator(iterable.iterator());
}
@Override
public void forEach(Consumer super T> action) {
iterable.forEach(action);
}
@SuppressWarnings("unchecked") // safe upcast, assuming no one has a crazy Spliterator subclass
@Override
public Spliterator spliterator() {
return (Spliterator) iterable.spliterator();
}
@Override
public String toString() {
return iterable.toString();
}
// no equals and hashCode; it would break the contract!
}
/** Returns the number of elements in {@code iterable}. */
public static int size(Iterable> iterable) {
return (iterable instanceof Collection)
? ((Collection>) iterable).size()
: Iterators.size(iterable.iterator());
}
/**
* Returns {@code true} if {@code iterable} contains any element {@code o} for which {@code
* Objects.equals(o, element)} would return {@code true}. Otherwise returns {@code false}, even in
* cases where {@link Collection#contains} might throw {@link NullPointerException} or {@link
* ClassCastException}.
*/
public static boolean contains(Iterable> iterable, Object element) {
if (iterable instanceof Collection) {
Collection> collection = (Collection>) iterable;
return Collections2.safeContains(collection, element);
}
return Iterators.contains(iterable.iterator(), element);
}
/**
* Removes, from an iterable, every element that belongs to the provided collection.
*
* This method calls {@link Collection#removeAll} if {@code iterable} is a collection, and
* {@link Iterators#removeAll} otherwise.
*
* @param removeFrom the iterable to (potentially) remove elements from
* @param elementsToRemove the elements to remove
* @return {@code true} if any element was removed from {@code iterable}
*/
public static boolean removeAll(Iterable> removeFrom, Collection> elementsToRemove) {
return (removeFrom instanceof Collection)
? ((Collection>) removeFrom).removeAll(checkNotNull(elementsToRemove))
: Iterators.removeAll(removeFrom.iterator(), elementsToRemove);
}
/**
* Removes, from an iterable, every element that does not belong to the provided collection.
*
*
This method calls {@link Collection#retainAll} if {@code iterable} is a collection, and
* {@link Iterators#retainAll} otherwise.
*
* @param removeFrom the iterable to (potentially) remove elements from
* @param elementsToRetain the elements to retain
* @return {@code true} if any element was removed from {@code iterable}
*/
public static boolean retainAll(Iterable> removeFrom, Collection> elementsToRetain) {
return (removeFrom instanceof Collection)
? ((Collection>) removeFrom).retainAll(checkNotNull(elementsToRetain))
: Iterators.retainAll(removeFrom.iterator(), elementsToRetain);
}
/**
* Removes, from an iterable, every element that satisfies the provided predicate.
*
*
Removals may or may not happen immediately as each element is tested against the predicate.
* The behavior of this method is not specified if {@code predicate} is dependent on {@code
* removeFrom}.
*
*
Java 8 users: if {@code removeFrom} is a {@link Collection}, use {@code
* removeFrom.removeIf(predicate)} instead.
*
* @param removeFrom the iterable to (potentially) remove elements from
* @param predicate a predicate that determines whether an element should be removed
* @return {@code true} if any elements were removed from the iterable
* @throws UnsupportedOperationException if the iterable does not support {@code remove()}.
* @since 2.0
*/
public static boolean removeIf(Iterable removeFrom, Predicate super T> predicate) {
if (removeFrom instanceof Collection) {
return ((Collection) removeFrom).removeIf(predicate);
}
return Iterators.removeIf(removeFrom.iterator(), predicate);
}
/** Removes and returns the first matching element, or returns {@code null} if there is none. */
static T removeFirstMatching(
Iterable removeFrom, Predicate super T> predicate) {
checkNotNull(predicate);
Iterator iterator = removeFrom.iterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (predicate.apply(next)) {
iterator.remove();
return next;
}
}
return null;
}
/**
* Determines whether two iterables contain equal elements in the same order. More specifically,
* this method returns {@code true} if {@code iterable1} and {@code iterable2} contain the same
* number of elements and every element of {@code iterable1} is equal to the corresponding element
* of {@code iterable2}.
*/
public static boolean elementsEqual(Iterable> iterable1, Iterable> iterable2) {
if (iterable1 instanceof Collection && iterable2 instanceof Collection) {
Collection> collection1 = (Collection>) iterable1;
Collection> collection2 = (Collection>) iterable2;
if (collection1.size() != collection2.size()) {
return false;
}
}
return Iterators.elementsEqual(iterable1.iterator(), iterable2.iterator());
}
/**
* Returns a string representation of {@code iterable}, with the format {@code [e1, e2, ..., en]}
* (that is, identical to {@link java.util.Arrays Arrays}{@code
* .toString(Iterables.toArray(iterable))}). Note that for most implementations of {@link
* Collection}, {@code collection.toString()} also gives the same result, but that behavior is not
* generally guaranteed.
*/
public static String toString(Iterable> iterable) {
return Iterators.toString(iterable.iterator());
}
/**
* Returns the single element contained in {@code iterable}.
*
* Java 8 users: the {@code Stream} equivalent to this method is {@code
* stream.collect(MoreCollectors.onlyElement())}.
*
* @throws NoSuchElementException if the iterable is empty
* @throws IllegalArgumentException if the iterable contains multiple elements
*/
public static T getOnlyElement(Iterable iterable) {
return Iterators.getOnlyElement(iterable.iterator());
}
/**
* Returns the single element contained in {@code iterable}, or {@code defaultValue} if the
* iterable is empty.
*
* Java 8 users: the {@code Stream} equivalent to this method is {@code
* stream.collect(MoreCollectors.toOptional()).orElse(defaultValue)}.
*
* @throws IllegalArgumentException if the iterator contains multiple elements
*/
public static T getOnlyElement(
Iterable extends T> iterable, T defaultValue) {
return Iterators.getOnlyElement(iterable.iterator(), defaultValue);
}
/**
* Copies an iterable's elements into an array.
*
* @param iterable the iterable to copy
* @param type the type of the elements
* @return a newly-allocated array into which all the elements of the iterable have been copied
*/
@GwtIncompatible // Array.newInstance(Class, int)
public static T[] toArray(Iterable extends T> iterable, Class type) {
return toArray(iterable, ObjectArrays.newArray(type, 0));
}
static T[] toArray(Iterable extends T> iterable, T[] array) {
Collection extends T> collection = castOrCopyToCollection(iterable);
return collection.toArray(array);
}
/**
* Copies an iterable's elements into an array.
*
* @param iterable the iterable to copy
* @return a newly-allocated array into which all the elements of the iterable have been copied
*/
static Object[] toArray(Iterable> iterable) {
return castOrCopyToCollection(iterable).toArray();
}
/**
* Converts an iterable into a collection. If the iterable is already a collection, it is
* returned. Otherwise, an {@link java.util.ArrayList} is created with the contents of the
* iterable in the same iteration order.
*/
private static Collection castOrCopyToCollection(Iterable iterable) {
return (iterable instanceof Collection)
? (Collection) iterable
: Lists.newArrayList(iterable.iterator());
}
/**
* Adds all elements in {@code iterable} to {@code collection}.
*
* @return {@code true} if {@code collection} was modified as a result of this operation.
*/
public static boolean addAll(Collection addTo, Iterable extends T> elementsToAdd) {
if (elementsToAdd instanceof Collection) {
Collection extends T> c = Collections2.cast(elementsToAdd);
return addTo.addAll(c);
}
return Iterators.addAll(addTo, checkNotNull(elementsToAdd).iterator());
}
/**
* Returns the number of elements in the specified iterable that equal the specified object. This
* implementation avoids a full iteration when the iterable is a {@link Multiset} or {@link Set}.
*
* Java 8 users: In most cases, the {@code Stream} equivalent of this method is {@code
* stream.filter(element::equals).count()}. If {@code element} might be null, use {@code
* stream.filter(Predicate.isEqual(element)).count()} instead.
*
* @see java.util.Collections#frequency(Collection, Object) Collections.frequency(Collection,
* Object)
*/
public static int frequency(Iterable> iterable, Object element) {
if ((iterable instanceof Multiset)) {
return ((Multiset>) iterable).count(element);
} else if ((iterable instanceof Set)) {
return ((Set>) iterable).contains(element) ? 1 : 0;
}
return Iterators.frequency(iterable.iterator(), element);
}
/**
* Returns an iterable whose iterators cycle indefinitely over the elements of {@code iterable}.
*
*
That iterator supports {@code remove()} if {@code iterable.iterator()} does. After {@code
* remove()} is called, subsequent cycles omit the removed element, which is no longer in {@code
* iterable}. The iterator's {@code hasNext()} method returns {@code true} until {@code iterable}
* is empty.
*
*
Warning: Typical uses of the resulting iterator may produce an infinite loop. You
* should use an explicit {@code break} or be certain that you will eventually remove all the
* elements.
*
*
To cycle over the iterable {@code n} times, use the following: {@code
* Iterables.concat(Collections.nCopies(n, iterable))}
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code
* Stream.generate(() -> iterable).flatMap(Streams::stream)}.
*/
public static Iterable cycle(final Iterable iterable) {
checkNotNull(iterable);
return new FluentIterable() {
@Override
public Iterator iterator() {
return Iterators.cycle(iterable);
}
@Override
public Spliterator spliterator() {
return Stream.generate(() -> iterable).flatMap(Streams::stream).spliterator();
}
@Override
public String toString() {
return iterable.toString() + " (cycled)";
}
};
}
/**
* Returns an iterable whose iterators cycle indefinitely over the provided elements.
*
* After {@code remove} is invoked on a generated iterator, the removed element will no longer
* appear in either that iterator or any other iterator created from the same source iterable.
* That is, this method behaves exactly as {@code Iterables.cycle(Lists.newArrayList(elements))}.
* The iterator's {@code hasNext} method returns {@code true} until all of the original elements
* have been removed.
*
*
Warning: Typical uses of the resulting iterator may produce an infinite loop. You
* should use an explicit {@code break} or be certain that you will eventually remove all the
* elements.
*
*
To cycle over the elements {@code n} times, use the following: {@code
* Iterables.concat(Collections.nCopies(n, Arrays.asList(elements)))}
*
*
Java 8 users: If passing a single element {@code e}, the {@code Stream} equivalent of
* this method is {@code Stream.generate(() -> e)}. Otherwise, put the elements in a collection
* and use {@code Stream.generate(() -> collection).flatMap(Collection::stream)}.
*/
@SafeVarargs
public static Iterable cycle(T... elements) {
return cycle(Lists.newArrayList(elements));
}
/**
* Combines two iterables into a single iterable. The returned iterable has an iterator that
* traverses the elements in {@code a}, followed by the elements in {@code b}. The source
* iterators are not polled until necessary.
*
* The returned iterable's iterator supports {@code remove()} when the corresponding input
* iterator supports it.
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code Stream.concat(a,
* b)}.
*/
public static Iterable concat(Iterable extends T> a, Iterable extends T> b) {
return FluentIterable.concat(a, b);
}
/**
* Combines three iterables into a single iterable. The returned iterable has an iterator that
* traverses the elements in {@code a}, followed by the elements in {@code b}, followed by the
* elements in {@code c}. The source iterators are not polled until necessary.
*
* The returned iterable's iterator supports {@code remove()} when the corresponding input
* iterator supports it.
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code
* Streams.concat(a, b, c)}.
*/
public static Iterable concat(
Iterable extends T> a, Iterable extends T> b, Iterable extends T> c) {
return FluentIterable.concat(a, b, c);
}
/**
* Combines four iterables into a single iterable. The returned iterable has an iterator that
* traverses the elements in {@code a}, followed by the elements in {@code b}, followed by the
* elements in {@code c}, followed by the elements in {@code d}. The source iterators are not
* polled until necessary.
*
* The returned iterable's iterator supports {@code remove()} when the corresponding input
* iterator supports it.
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code
* Streams.concat(a, b, c, d)}.
*/
public static Iterable concat(
Iterable extends T> a,
Iterable extends T> b,
Iterable extends T> c,
Iterable extends T> d) {
return FluentIterable.concat(a, b, c, d);
}
/**
* Combines multiple iterables into a single iterable. The returned iterable has an iterator that
* traverses the elements of each iterable in {@code inputs}. The input iterators are not polled
* until necessary.
*
* The returned iterable's iterator supports {@code remove()} when the corresponding input
* iterator supports it.
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code
* Streams.concat(...)}.
*
* @throws NullPointerException if any of the provided iterables is null
*/
@SafeVarargs
public static Iterable concat(Iterable extends T>... inputs) {
return FluentIterable.concat(inputs);
}
/**
* Combines multiple iterables into a single iterable. The returned iterable has an iterator that
* traverses the elements of each iterable in {@code inputs}. The input iterators are not polled
* until necessary.
*
* The returned iterable's iterator supports {@code remove()} when the corresponding input
* iterator supports it. The methods of the returned iterable may throw {@code
* NullPointerException} if any of the input iterators is null.
*
*
Java 8 users: The {@code Stream} equivalent of this method is {@code
* streamOfStreams.flatMap(s -> s)}.
*/
public static Iterable concat(Iterable extends Iterable extends T>> inputs) {
return FluentIterable.concat(inputs);
}
/**
* Divides an iterable into unmodifiable sublists of the given size (the final iterable may be
* smaller). For example, partitioning an iterable containing {@code [a, b, c, d, e]} with a
* partition size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer iterable containing two
* inner lists of three and two elements, all in the original order.
*
* Iterators returned by the returned iterable do not support the {@link Iterator#remove()}
* method. The returned lists implement {@link RandomAccess}, whether or not the input list does.
*
*
Note: if {@code iterable} is a {@link List}, use {@link Lists#partition(List, int)}
* instead.
*
* @param iterable the iterable to return a partitioned view of
* @param size the desired size of each partition (the last may be smaller)
* @return an iterable of unmodifiable lists containing the elements of {@code iterable} divided
* into partitions
* @throws IllegalArgumentException if {@code size} is nonpositive
*/
public static Iterable> partition(final Iterable iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
return new FluentIterable>() {
@Override
public Iterator> iterator() {
return Iterators.partition(iterable.iterator(), size);
}
};
}
/**
* Divides an iterable into unmodifiable sublists of the given size, padding the final iterable
* with null values if necessary. For example, partitioning an iterable containing {@code [a, b,
* c, d, e]} with a partition size of 3 yields {@code [[a, b, c], [d, e, null]]} -- an outer
* iterable containing two inner lists of three elements each, all in the original order.
*
* Iterators returned by the returned iterable do not support the {@link Iterator#remove()}
* method.
*
* @param iterable the iterable to return a partitioned view of
* @param size the desired size of each partition
* @return an iterable of unmodifiable lists containing the elements of {@code iterable} divided
* into partitions (the final iterable may have trailing null elements)
* @throws IllegalArgumentException if {@code size} is nonpositive
*/
public static Iterable> paddedPartition(final Iterable iterable, final int size) {
checkNotNull(iterable);
checkArgument(size > 0);
return new FluentIterable>() {
@Override
public Iterator> iterator() {
return Iterators.paddedPartition(iterable.iterator(), size);
}
};
}
/**
* Returns a view of {@code unfiltered} containing all elements that satisfy the input predicate
* {@code retainIfTrue}. The returned iterable's iterator does not support {@code remove()}.
*
* {@code Stream} equivalent: {@link Stream#filter}.
*/
public static Iterable filter(
final Iterable unfiltered, final Predicate super T> retainIfTrue) {
checkNotNull(unfiltered);
checkNotNull(retainIfTrue);
return new FluentIterable() {
@Override
public Iterator iterator() {
return Iterators.filter(unfiltered.iterator(), retainIfTrue);
}
@Override
public void forEach(Consumer super T> action) {
checkNotNull(action);
unfiltered.forEach(
(T a) -> {
if (retainIfTrue.test(a)) {
action.accept(a);
}
});
}
@Override
public Spliterator spliterator() {
return CollectSpliterators.filter(unfiltered.spliterator(), retainIfTrue);
}
};
}
/**
* Returns a view of {@code unfiltered} containing all elements that are of the type {@code
* desiredType}. The returned iterable's iterator does not support {@code remove()}.
*
* {@code Stream} equivalent: {@code stream.filter(type::isInstance).map(type::cast)}.
* This does perform a little more work than necessary, so another option is to insert an
* unchecked cast at some later point:
*
*
* {@code @SuppressWarnings("unchecked") // safe because of ::isInstance check
* ImmutableList result =
* (ImmutableList) stream.filter(NewType.class::isInstance).collect(toImmutableList());}
*
*/
@SuppressWarnings("unchecked")
@GwtIncompatible // Class.isInstance
public static Iterable filter(final Iterable> unfiltered, final Class desiredType) {
checkNotNull(unfiltered);
checkNotNull(desiredType);
return (Iterable) filter(unfiltered, Predicates.instanceOf(desiredType));
}
/**
* Returns {@code true} if any element in {@code iterable} satisfies the predicate.
*
* {@code Stream} equivalent: {@link Stream#anyMatch}.
*/
public static boolean any(Iterable iterable, Predicate super T> predicate) {
return Iterators.any(iterable.iterator(), predicate);
}
/**
* Returns {@code true} if every element in {@code iterable} satisfies the predicate. If {@code
* iterable} is empty, {@code true} is returned.
*
* {@code Stream} equivalent: {@link Stream#allMatch}.
*/
public static boolean all(Iterable iterable, Predicate super T> predicate) {
return Iterators.all(iterable.iterator(), predicate);
}
/**
* Returns the first element in {@code iterable} that satisfies the given predicate; use this
* method only when such an element is known to exist. If it is possible that no element
* will match, use {@link #tryFind} or {@link #find(Iterable, Predicate, Object)} instead.
*
* {@code Stream} equivalent: {@code stream.filter(predicate).findFirst().get()}
*
* @throws NoSuchElementException if no element in {@code iterable} matches the given predicate
*/
public static T find(Iterable iterable, Predicate super T> predicate) {
return Iterators.find(iterable.iterator(), predicate);
}
/**
* Returns the first element in {@code iterable} that satisfies the given predicate, or {@code
* defaultValue} if none found. Note that this can usually be handled more naturally using {@code
* tryFind(iterable, predicate).or(defaultValue)}.
*
* {@code Stream} equivalent: {@code
* stream.filter(predicate).findFirst().orElse(defaultValue)}
*
* @since 7.0
*/
public static T find(
Iterable extends T> iterable, Predicate super T> predicate, T defaultValue) {
return Iterators.find(iterable.iterator(), predicate, defaultValue);
}
/**
* Returns an {@link Optional} containing the first element in {@code iterable} that satisfies the
* given predicate, if such an element exists.
*
* Warning: avoid using a {@code predicate} that matches {@code null}. If {@code null}
* is matched in {@code iterable}, a NullPointerException will be thrown.
*
*
{@code Stream} equivalent: {@code stream.filter(predicate).findFirst()}
*
* @since 11.0
*/
public static Optional tryFind(Iterable iterable, Predicate super T> predicate) {
return Iterators.tryFind(iterable.iterator(), predicate);
}
/**
* Returns the index in {@code iterable} of the first element that satisfies the provided {@code
* predicate}, or {@code -1} if the Iterable has no such elements.
*
* More formally, returns the lowest index {@code i} such that {@code
* predicate.apply(Iterables.get(iterable, i))} returns {@code true}, or {@code -1} if there is no
* such index.
*
* @since 2.0
*/
public static int indexOf(Iterable iterable, Predicate super T> predicate) {
return Iterators.indexOf(iterable.iterator(), predicate);
}
/**
* Returns a view containing the result of applying {@code function} to each element of {@code
* fromIterable}.
*
* The returned iterable's iterator supports {@code remove()} if {@code fromIterable}'s
* iterator does. After a successful {@code remove()} call, {@code fromIterable} no longer
* contains the corresponding element.
*
*
If the input {@code Iterable} is known to be a {@code List} or other {@code Collection},
* consider {@link Lists#transform} and {@link Collections2#transform}.
*
*
{@code Stream} equivalent: {@link Stream#map}
*/
public static Iterable transform(
final Iterable fromIterable, final Function super F, ? extends T> function) {
checkNotNull(fromIterable);
checkNotNull(function);
return new FluentIterable() {
@Override
public Iterator iterator() {
return Iterators.transform(fromIterable.iterator(), function);
}
@Override
public void forEach(Consumer super T> action) {
checkNotNull(action);
fromIterable.forEach((F f) -> action.accept(function.apply(f)));
}
@Override
public Spliterator spliterator() {
return CollectSpliterators.map(fromIterable.spliterator(), function);
}
};
}
/**
* Returns the element at the specified position in an iterable.
*
* {@code Stream} equivalent: {@code stream.skip(position).findFirst().get()} (throws
* {@code NoSuchElementException} if out of bounds)
*
* @param position position of the element to return
* @return the element at the specified position in {@code iterable}
* @throws IndexOutOfBoundsException if {@code position} is negative or greater than or equal to
* the size of {@code iterable}
*/
public static T get(Iterable iterable, int position) {
checkNotNull(iterable);
return (iterable instanceof List)
? ((List) iterable).get(position)
: Iterators.get(iterable.iterator(), position);
}
/**
* Returns the element at the specified position in an iterable or a default value otherwise.
*
* {@code Stream} equivalent: {@code
* stream.skip(position).findFirst().orElse(defaultValue)} (returns the default value if the index
* is out of bounds)
*
* @param position position of the element to return
* @param defaultValue the default value to return if {@code position} is greater than or equal to
* the size of the iterable
* @return the element at the specified position in {@code iterable} or {@code defaultValue} if
* {@code iterable} contains fewer than {@code position + 1} elements.
* @throws IndexOutOfBoundsException if {@code position} is negative
* @since 4.0
*/
public static T get(
Iterable extends T> iterable, int position, T defaultValue) {
checkNotNull(iterable);
Iterators.checkNonnegative(position);
if (iterable instanceof List) {
List extends T> list = Lists.cast(iterable);
return (position < list.size()) ? list.get(position) : defaultValue;
} else {
Iterator extends T> iterator = iterable.iterator();
Iterators.advance(iterator, position);
return Iterators.getNext(iterator, defaultValue);
}
}
/**
* Returns the first element in {@code iterable} or {@code defaultValue} if the iterable is empty.
* The {@link Iterators} analog to this method is {@link Iterators#getNext}.
*
* If no default value is desired (and the caller instead wants a {@link
* NoSuchElementException} to be thrown), it is recommended that {@code
* iterable.iterator().next()} is used instead.
*
*
To get the only element in a single-element {@code Iterable}, consider using {@link
* #getOnlyElement(Iterable)} or {@link #getOnlyElement(Iterable, Object)} instead.
*
*
{@code Stream} equivalent: {@code stream.findFirst().orElse(defaultValue)}
*
* @param defaultValue the default value to return if the iterable is empty
* @return the first element of {@code iterable} or the default value
* @since 7.0
*/
public static T getFirst(Iterable extends T> iterable, T defaultValue) {
return Iterators.getNext(iterable.iterator(), defaultValue);
}
/**
* Returns the last element of {@code iterable}. If {@code iterable} is a {@link List} with {@link
* RandomAccess} support, then this operation is guaranteed to be {@code O(1)}.
*
* {@code Stream} equivalent: {@link Streams#findLast Streams.findLast(stream).get()}
*
* @return the last element of {@code iterable}
* @throws NoSuchElementException if the iterable is empty
*/
public static T getLast(Iterable iterable) {
// TODO(kevinb): Support a concurrently modified collection?
if (iterable instanceof List) {
List list = (List) iterable;
if (list.isEmpty()) {
throw new NoSuchElementException();
}
return getLastInNonemptyList(list);
}
return Iterators.getLast(iterable.iterator());
}
/**
* Returns the last element of {@code iterable} or {@code defaultValue} if the iterable is empty.
* If {@code iterable} is a {@link List} with {@link RandomAccess} support, then this operation is
* guaranteed to be {@code O(1)}.
*
* {@code Stream} equivalent: {@code Streams.findLast(stream).orElse(defaultValue)}
*
* @param defaultValue the value to return if {@code iterable} is empty
* @return the last element of {@code iterable} or the default value
* @since 3.0
*/
public static T getLast(Iterable extends T> iterable, T defaultValue) {
if (iterable instanceof Collection) {
Collection extends T> c = Collections2.cast(iterable);
if (c.isEmpty()) {
return defaultValue;
} else if (iterable instanceof List) {
return getLastInNonemptyList(Lists.cast(iterable));
}
}
return Iterators.getLast(iterable.iterator(), defaultValue);
}
private static T getLastInNonemptyList(List list) {
return list.get(list.size() - 1);
}
/**
* Returns a view of {@code iterable} that skips its first {@code numberToSkip} elements. If
* {@code iterable} contains fewer than {@code numberToSkip} elements, the returned iterable skips
* all of its elements.
*
* Modifications to the underlying {@link Iterable} before a call to {@code iterator()} are
* reflected in the returned iterator. That is, the iterator skips the first {@code numberToSkip}
* elements that exist when the {@code Iterator} is created, not when {@code skip()} is called.
*
*
The returned iterable's iterator supports {@code remove()} if the iterator of the underlying
* iterable supports it. Note that it is not possible to delete the last skipped element by
* immediately calling {@code remove()} on that iterator, as the {@code Iterator} contract states
* that a call to {@code remove()} before a call to {@code next()} will throw an {@link
* IllegalStateException}.
*
*
{@code Stream} equivalent: {@link Stream#skip}
*
* @since 3.0
*/
public static Iterable skip(final Iterable iterable, final int numberToSkip) {
checkNotNull(iterable);
checkArgument(numberToSkip >= 0, "number to skip cannot be negative");
return new FluentIterable() {
@Override
public Iterator iterator() {
if (iterable instanceof List) {
final List list = (List) iterable;
int toSkip = Math.min(list.size(), numberToSkip);
return list.subList(toSkip, list.size()).iterator();
}
final Iterator iterator = iterable.iterator();
Iterators.advance(iterator, numberToSkip);
/*
* We can't just return the iterator because an immediate call to its
* remove() method would remove one of the skipped elements instead of
* throwing an IllegalStateException.
*/
return new Iterator() {
boolean atStart = true;
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public T next() {
T result = iterator.next();
atStart = false; // not called if next() fails
return result;
}
@Override
public void remove() {
checkRemove(!atStart);
iterator.remove();
}
};
}
@Override
public Spliterator spliterator() {
if (iterable instanceof List) {
final List list = (List) iterable;
int toSkip = Math.min(list.size(), numberToSkip);
return list.subList(toSkip, list.size()).spliterator();
} else {
return Streams.stream(iterable).skip(numberToSkip).spliterator();
}
}
};
}
/**
* Returns a view of {@code iterable} containing its first {@code limitSize} elements. If {@code
* iterable} contains fewer than {@code limitSize} elements, the returned view contains all of its
* elements. The returned iterable's iterator supports {@code remove()} if {@code iterable}'s
* iterator does.
*
* {@code Stream} equivalent: {@link Stream#limit}
*
* @param iterable the iterable to limit
* @param limitSize the maximum number of elements in the returned iterable
* @throws IllegalArgumentException if {@code limitSize} is negative
* @since 3.0
*/
public static Iterable limit(final Iterable iterable, final int limitSize) {
checkNotNull(iterable);
checkArgument(limitSize >= 0, "limit is negative");
return new FluentIterable() {
@Override
public Iterator iterator() {
return Iterators.limit(iterable.iterator(), limitSize);
}
@Override
public Spliterator spliterator() {
return Streams.stream(iterable).limit(limitSize).spliterator();
}
};
}
/**
* Returns a view of the supplied iterable that wraps each generated {@link Iterator} through
* {@link Iterators#consumingIterator(Iterator)}.
*
* Note: If {@code iterable} is a {@link Queue}, the returned iterable will get entries from
* {@link Queue#remove()} since {@link Queue}'s iteration order is undefined. Calling {@link
* Iterator#hasNext()} on a generated iterator from the returned iterable may cause an item to be
* immediately dequeued for return on a subsequent call to {@link Iterator#next()}.
*
* @param iterable the iterable to wrap
* @return a view of the supplied iterable that wraps each generated iterator through {@link
* Iterators#consumingIterator(Iterator)}; for queues, an iterable that generates iterators
* that return and consume the queue's elements in queue order
* @see Iterators#consumingIterator(Iterator)
* @since 2.0
*/
public static Iterable consumingIterable(final Iterable iterable) {
checkNotNull(iterable);
return new FluentIterable() {
@Override
public Iterator iterator() {
return (iterable instanceof Queue)
? new ConsumingQueueIterator<>((Queue) iterable)
: Iterators.consumingIterator(iterable.iterator());
}
@Override
public String toString() {
return "Iterables.consumingIterable(...)";
}
};
}
// Methods only in Iterables, not in Iterators
/**
* Determines if the given iterable contains no elements.
*
* There is no precise {@link Iterator} equivalent to this method, since one can only ask an
* iterator whether it has any elements remaining (which one does using {@link
* Iterator#hasNext}).
*
*
{@code Stream} equivalent: {@code !stream.findAny().isPresent()}
*
* @return {@code true} if the iterable contains no elements
*/
public static boolean isEmpty(Iterable> iterable) {
if (iterable instanceof Collection) {
return ((Collection>) iterable).isEmpty();
}
return !iterable.iterator().hasNext();
}
/**
* Returns an iterable over the merged contents of all given {@code iterables}. Equivalent entries
* will not be de-duplicated.
*
*
Callers must ensure that the source {@code iterables} are in non-descending order as this
* method does not sort its input.
*
*
For any equivalent elements across all {@code iterables}, it is undefined which element is
* returned first.
*
* @since 11.0
*/
@Beta
public static Iterable mergeSorted(
final Iterable extends Iterable extends T>> iterables,
final Comparator super T> comparator) {
checkNotNull(iterables, "iterables");
checkNotNull(comparator, "comparator");
Iterable iterable =
new FluentIterable() {
@Override
public Iterator iterator() {
return Iterators.mergeSorted(
Iterables.transform(iterables, Iterables.toIterator()), comparator);
}
};
return new UnmodifiableIterable<>(iterable);
}
// TODO(user): Is this the best place for this? Move to fluent functions?
// Useful as a public method?
static Function, Iterator extends T>> toIterator() {
return new Function, Iterator extends T>>() {
@Override
public Iterator extends T> apply(Iterable extends T> iterable) {
return iterable.iterator();
}
};
}
}