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

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> 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> 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> 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 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 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