com.bbn.bue.common.collections.IterableUtils Maven / Gradle / Ivy
The newest version!
package com.bbn.bue.common.collections;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Iterator;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public final class IterableUtils {
private IterableUtils() {
}
/**
* Promotes a predicate over T to a predicate over Iterable that returns true if an only if any
* the predicate is true for any of the iterable's contents.
*/
public static Predicate> anyPredicate(final Predicate pred) {
return new Predicate>() {
@Override
public boolean apply(final Iterable iter) {
return com.google.common.collect.Iterables.any(iter, pred);
}
};
}
/**
* Promotes a predicate over T to a predicate over Iterable that returns true if an only if any
* the predicate is true for any of the iterable's contents.
*/
public static Predicate> allPredicate(final Predicate pred) {
return new Predicate>() {
@Override
public boolean apply(final Iterable iter) {
return com.google.common.collect.Iterables.all(iter, pred);
}
};
}
/**
* Applys a one-to-many transform to each element of an {@code Iterable} and concatenates all the
* results into one {@code Iterable}. This is done lazily.
*
* @deprecated Prefer {@link FluentIterable#transformAndConcat(Function)} now that it
* exists.
*/
@Deprecated
public static Iterable applyOneToManyTransform(
final Iterable input,
final Function super InType, ? extends Iterable> function) {
return FluentIterable.from(input)
.transformAndConcat(function);
}
/**
* An implementation of Python's zip.
*/
public static Iterable> zip(final Iterable iter1,
final Iterable iter2) {
return new ZipIterable(iter1, iter2);
}
public static Iterable> zip(
final Iterable extends Iterable extends T>> iterables) {
return new MultiZipIterable(iterables);
}
/**
* An iterable for iteration of two Iterables paired up with zip
*
* @author rgabbard
*/
public static final class ZipIterable implements Iterable> {
private ZipIterable(final Iterable iter1, final Iterable iter2) {
this.iterable1 = checkNotNull(iter1);
this.iterable2 = checkNotNull(iter2);
}
private final Iterable iterable1;
private final Iterable iterable2;
@Override
public Iterator> iterator() {
final Iterator iter1 = iterable1.iterator();
final Iterator iter2 = iterable2.iterator();
return new UnmodifiableIterator>() {
int elementsRead = 0;
@Override
public boolean hasNext() {
if (iter1.hasNext() != iter2.hasNext()) {
final String shorterOne = iter1.hasNext() ? "right" : "left";
throw new RuntimeException(
String.format(
"Iterable length mismatch in zip: %s has %d elements, but the other has more.",
shorterOne, elementsRead));
}
return iter1.hasNext();
}
@Override
public ZipPair next() {
++elementsRead;
return new ZipPair(iter1.next(), iter2.next());
}
};
}
public static ZipIterable zip(final Iterable iter1, final Iterable iter2) {
return new ZipIterable(iter1, iter2);
}
}
/**
* Represents a matching pair of items from two zipped iterators.
*
* @author rgabbard
*/
public static final class ZipPair {
public ZipPair(final X first, final Y second) {
this.first = first;
this.second = second;
}
public X first() {
return first;
}
public Y second() {
return second;
}
@Override
public String toString() {
return String.format("(%s,%s)", first, second);
}
@Override
public int hashCode() {
return Objects.hashCode(first, second);
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ZipPair)) {
return false;
}
final ZipPair, ?> other = (ZipPair, ?>) obj;
return Objects.equal(first, other.first)
&& Objects.equal(second, other.second);
}
public static ZipPair from(final X x, final Y y) {
return new ZipPair(x, y);
}
private final X first;
private final Y second;
}
/**
* An iterable for iteration of many Iterables paired up with zip.
*
* @author rgabbard
*/
public static final class MultiZipIterable implements Iterable> {
private MultiZipIterable(final Iterable extends Iterable extends T>> iterables) {
this.iterables = ImmutableList.copyOf(iterables);
checkArgument(!this.iterables.isEmpty());
}
private final List> iterables;
@Override
public Iterator> iterator() {
final ImmutableList.Builder> iteratorsB = ImmutableList.builder();
for (final Iterable extends T> iterable : iterables) {
iteratorsB.add(iterable.iterator());
}
final ImmutableList> iterators = iteratorsB.build();
return new UnmodifiableIterator>() {
@Override
public boolean hasNext() {
if (!allTheSame(Lists.transform(iterators, HasNext))) {
throw new RuntimeException("Iterable length mismatch in zip: %s is longer.");
}
return iterators.get(0).hasNext();
}
@Override
public List next() {
final ImmutableList.Builder ret = ImmutableList.builder();
for (final Iterator extends T> it : iterators) {
ret.add(it.next());
}
return ret.build();
}
};
}
}
/**
* Two argument function to be used for reduction
*
* @author mshafir
*/
public interface Function2 {
B apply(B b, A a);
}
/**
* reduces an iterable to a single value starting from an initial value and applying down the
* iterable.
*/
public static B reduce(final Iterable iterable,
final B initial, final Function2 func) {
B b = initial;
for (final A item : iterable) {
b = func.apply(b, item);
}
return b;
}
public static final Function2 SumReducer = new Function2() {
@Override
public Number apply(final Number a, final Number b) {
return a.doubleValue() + b.doubleValue();
}
};
public static final Function2 SumReducerInt =
new Function2() {
@Override
public Integer apply(final Integer a, final Integer b) {
return a + b;
}
};
public static final Function, Number> Sum =
new Function, Number>() {
@Override
public Number apply(final Iterable it) {
return reduce(it, 0, SumReducer);
}
};
public static final Function, Integer> IntSum =
new Function, Integer>() {
@Override
public Integer apply(final Iterable it) {
return reduce(it, 0, SumReducerInt);
}
};
/**
* Transforms an Iterable to a Map where each item is mapped to its zero-indexed
* position in the Iterable's sequence. If an item occurs twice, an IllegalArgumentException will
* be thrown.
*/
public static ImmutableMap itemToIndexMap(final Iterable sequence) {
return itemToIndexMapStartingFrom(sequence, 0);
}
/**
* Transforms an Iterable to a Map where each item is mapped to its position in the
* Iterable's sequence, where the first position is given index {@code startFrom}. If an item
* occurs twice, an IllegalArgumentException will be thrown.
*/
public static ImmutableMap itemToIndexMapStartingFrom(final Iterable sequence,
int startFrom) {
final ImmutableMap.Builder ret = ImmutableMap.builder();
int idx = startFrom;
for (final T item : sequence) {
ret.put(item, idx);
++idx;
}
return ret.build();
}
/**
* Transforms an Iterable to a Map where each item is mapped to its zero-indexed
* position(s) in the Iterable's sequence.
*/
public static ImmutableMultimap itemToIndexMultimap(
Iterable iterable) {
final ImmutableMultimap.Builder ret = ImmutableMultimap.builder();
int idx = 0;
for (final T x : iterable) {
ret.put(x, idx++);
}
return ret.build();
}
/**
* Given a paired sequence of Iterables, produce a map with keys from the first and values from
* the second. An exception will be raised if the Iterables have different numbers of elements, or
* if there are multiple mappings for the same key.
*/
public static ImmutableMap mapFromPairedKeyValueSequences(
final Iterable keys, final Iterable values) {
final ImmutableMap.Builder builder = ImmutableMap.builder();
for (final ZipPair pair : zip(keys, values)) {
builder.put(pair.first(), pair.second());
}
return builder.build();
}
public static final Function, Boolean> HasNext =
new Function, Boolean>() {
@Override
public Boolean apply(final Iterator> x) {
return x.hasNext();
}
};
/**
* Prefer allEqual, whose name is less ambiguous between equality and identity
*
* @deprecated
*/
@Deprecated
public static boolean allTheSame(final Iterable iterable) {
if (Iterables.isEmpty(iterable)) {
return true;
}
final T reference = Iterables.getFirst(iterable, null);
for (final T x : iterable) {
if (!x.equals(reference)) {
return false;
}
}
return true;
}
/**
* Returns whether all the items in the iterable are equal to one another by {@code .equals()}.
* Returns true for an empty iterable.
*/
public static boolean allEqual(final Iterable iterable) {
if (Iterables.isEmpty(iterable)) {
return true;
}
final T reference = Iterables.getFirst(iterable, null);
for (final T x : iterable) {
if (!x.equals(reference)) {
return false;
}
}
return true;
}
/**
* Returns true if and only if no two elements of the provided {@link Iterable} are equal to one
* another. Equality is determined by {@code .equals()}. Elements must have a {@code hashCode}
* consistent with their {@code equals} or the result is undefined.
*
* No element may be {@code null} or an exception will be thrown.
*/
public static boolean noneEqualForHashable(final Iterable iterable) {
return Iterables.size(iterable) == ImmutableSet.copyOf(iterable).size();
}
/**
* Returns a new {@link Iterable} which behaves like the provided {@code Iterable} except with a
* single extra element at the end. {@code item} may not be null.
*/
public static Iterable append(Iterable iterable, V item) {
return Iterables.concat(iterable, ImmutableList.of(item));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy