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

net.sf.staccatocommons.collections.iterable.Iterables Maven / Gradle / Ivy

Go to download

Collections library of the Staccato-Commons project, focused on providing new abstractions that mix object oriented and functional programming style for dealing with iterable objects.

The newest version!
/**
 *  Copyright (c) 2011, The Staccato-Commons Team
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; version 3 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 */

package net.sf.staccatocommons.collections.iterable;

import static net.sf.staccatocommons.collections.iterable.internal.IterablesInternal.*;
import static net.sf.staccatocommons.lang.tuple.Tuples.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import net.sf.staccatocommons.check.Ensure;
import net.sf.staccatocommons.defs.Applicable;
import net.sf.staccatocommons.defs.Applicable2;
import net.sf.staccatocommons.defs.Evaluable;
import net.sf.staccatocommons.defs.Evaluable2;
import net.sf.staccatocommons.defs.reduction.Accumulator;
import net.sf.staccatocommons.defs.reduction.Reduction;
import net.sf.staccatocommons.defs.tuple.Tuple2;
import net.sf.staccatocommons.defs.type.NumberType;
import net.sf.staccatocommons.lang.Option;
import net.sf.staccatocommons.lang.predicate.Equiv;
import net.sf.staccatocommons.lang.tuple.Tuples;
import net.sf.staccatocommons.restrictions.check.NonNull;
import net.sf.staccatocommons.restrictions.check.NotEmpty;
import net.sf.staccatocommons.restrictions.check.NotNegative;
import net.sf.staccatocommons.restrictions.check.Size;
import net.sf.staccatocommons.restrictions.processing.IgnoreRestrictions;

import org.apache.commons.lang.ObjectUtils;

/**
 * Class methods that complement the {@link java.util.Collections}
 * functionality, providing common algorithms for collections and iterables.
 * With no exception, all these methods are eager, that is, processing is
 * completely performed on method evaluation.
 * 
 * Otherwise stated, null collections, functors and iterables are prohibited as
 * parameter, but empty collections and iterables are allowed.
 * 
 * {@link Iterables} class contains only side-effect-free methods that do not
 * modify any of its arguments, and thus can be used with immutable collections.
 * 
 * For algorithms that modify the state of the input collections, see
 * {@link ModifiableIterables}. However, Stacatto-commons-collection API
 * recommends to avoid those methods when possible, as will fail with
 * unmodifiable collections.
 * 
 * @author flbulgarelli
 */
public class Iterables {

  /*
   * Filtering
   */

  /**
   * Selects all elements that evaluate to true.
   * 
   * @param iterable
   * @param predicate
   * @param 
   * @return a list containing only elements from the original iterable that
   *         evaluate to true
   */
  @NonNull
  public static  List filter(@NonNull Iterable iterable,
    @NonNull Evaluable predicate) {
    return filterInternal(iterable, predicate, new LinkedList());
  }

  /**
   * Selects at most the fist N elements from the iterable, according to its
   * iteration order.
   * 
   * @param 
   * @param iterable
   * @param amountOfElements
   * @return a new list containing at most the first N elements from original
   *         iterable.
   */
  @NonNull
  public static  List take(@NonNull Iterable iterable, @NotNegative int amountOfElements) {
    return takeInternal(iterable, amountOfElements, new ArrayList(amountOfElements));
  }

  /**
   * Answers the result of aggregating the given iterable elements
   * using the given function. The given {@link Iterable}
   * must not be empty.
   * 
   * @param 
   *          the {@link Iterable}'s elements type
   * @param iterable
   * @param function
   *          the aggregation {@link Applicable}
   * @return the result of aggregating the iterable's element
   */
  @NonNull
  @IgnoreRestrictions
  public static  A reduce(@NotEmpty Iterable iterable,
    @NonNull Applicable2 function) {
    Ensure.isNotNull("function", function);
    Iterator iter = iterable.iterator();
    if (!iter.hasNext())
      Ensure.fail(ITERABLE, iterable, "Must be not empty");
    A result = iter.next();
    while (iter.hasNext())
      result = function.apply(result, iter.next());
    return result;
  }

  /**
   * Answers the result of aggregating the given initial value and
   * the {@link Iterable} elements using the given function
   * 
   * As a particular case, if iterable is empty, this method
   * returns the initial value.
   * 
   * @param 
   *          the {@link Iterable}'s elements type
   * @param 
   *          the aggregated value type
   * @param iterable
   * @param initial
   * @param function
   *          the aggregation {@link Applicable}
   * @return the result of aggregating the initial value and the given
   *         iterable's elements.
   */
  @NonNull
  public static  B fold(@NonNull Iterable iterable, B initial,
    @NonNull Applicable2 function) {
    B result = initial;
    for (A element : iterable)
      result = function.apply(result, element);
    return result;
  }

  /**
   * Answers the result of aggregating the given iterable using the
   * given reduction
   * 
   * @param 
   *          the {@link Iterable}'s elements type
   * @param 
   *          the aggregated value type
   * @param iterable
   *          the iterable to aggregate
   * @param function
   *          the {@link Reduction} to apply to this iterable
   * @return the result of aggregating the initial value and the given
   *         iterable's elements.
   */
  @NonNull
  public static  B reduce(@NonNull Iterable iterable, @NonNull Reduction reduction) {
    Accumulator accum = reduction.newAccumulator();
    for (A element : iterable) {
      accum.accumulate(element);
    }
    return accum.value();
  }

  /*
   * Search
   */

  /**
   * Alternative version of {@link #findOrNone(Iterable, Evaluable)}, where the
   * element is returned if found, or a {@link NoSuchElementException} is thrown
   * otherwise
   * 
   * @param 
   * @param iterable
   * @param predicate
   * @return the element if found
   * @throws NoSuchElementException
   *           if no element matches the predicate
   */
  public static  A find(@NonNull Iterable iterable, @NonNull Evaluable predicate) {
    for (A o : iterable)
      if (predicate.eval(o))
        return o;
    throw new NoSuchElementException();
  }

  /**
   * Looks for a object that matches the given predicate. If such element does
   * not exist, or collection is empty, returns {@link Option#none()}. Otherwise
   * returns {@link Option#some(Object)}, for the first object found
   * 
   * @param 
   * @param iterable
   *          non null
   * @param predicate
   *          non null
   * @return None if no element matches the predicate or collection is empty, or
   *         some(element) if at least one exists
   */
  @NonNull
  public static  Option findOrNone(@NonNull Iterable iterable,
    @NonNull Evaluable predicate) {
    for (A o : iterable)
      if (predicate.eval(o))
        return Option.some(o);
    return Option.none();
  }

  /**
   * Returns the single element of the given collection. It must be of size 1,
   * otherwise, throws an IllegalArgumentException.
   * 
   * @param 
   *          the collection type
   * @param collection
   *          a single element (size==1) collection
   * @return The unique element of the collection
   */
  public static  A single(@Size(1) Collection collection) {
    return any(collection);
  }

  /**
   * Returns any element from this iterable, or throws a
   * {@link NoSuchElementException} it iterable is empty. Notice that
   * any does not mean random, it may return always the same
   * element - for example the first for a list -, but the exact element
   * returned from the iterable unspecified.
   * 
   * @param 
   * @param iterable
   * @throws NoSuchElementException
   *           if the iterable is empty
   * @return an element contained in the given iterable. This is nullable, if
   *         the iterables's iterator may return null.
   */
  public static  A any(@NonNull Iterable iterable) {
    return iterable.iterator().next();
  }

  /**
   * Gets any element of the given collection. Returns Option.some(element) if
   * not empty, or Option.none(), if empty.
   * 
   * @param 
   * @param iterable
   * @return some(element) if not empty, or none, otherwise.
   */
  @NonNull
  public static  Option anyOrNone(@NonNull Iterable iterable) {
    Iterator iterator = iterable.iterator();
    return iterator.hasNext() ? Option.some(iterator.next()) : Option. none();
  }

  /*
   * Validating
   */

  /**
   * Tests if all the elements of the given {@link Iterable} satisfy the given
   * predicate
   * 
   * @param 
   * @param iterable
   * @param predicate
   *          the predicate that will be used to evaluate each element
   * @return true if all the elements satisfy the given predicate,
   *         false otherwise. As a particular case of this rule,
   *         this method will return true for empty iterables,
   *         regardless of the predicate.
   */
  public static  boolean all(@NonNull Iterable iterable,
    @NonNull Evaluable predicate) {
    for (A o : iterable)
      if (!predicate.eval(o))
        return false;
    return true;
  }

  /**
   * Answers if all elements in the collection are equivalent using the given
   * equivTest.
   * 
   * @param 
   * @param iterable
   *          May be empty.
   * @param equivTest
   *          a predicate used to determine if two elements are equivalent
   * @return trueif all element are the same object.
   *         false otherwise. As a particular case of this rule, if
   *         this collection is empty or has only one element, it will return
   *         true.
   */
  public static  boolean allEquivBy(@NonNull Iterable iterable,
    Evaluable2 equivTest) {
    Iterator iter = iterable.iterator();
    if (!iter.hasNext())
      return true;
    A any = iter.next();
    while (iter.hasNext())
      if (!equivTest.eval(any, iter.next()))
        return false;
    return true;
  }

  /**
   * Answers if all elements in the collection are equal.
   * 
   * @param 
   * @param iterable
   *          non null. May be empty.
   * @return trueif all element are equal. false
   *         otherwise. As a particular case of this rule, if this collection is
   *         empty or has only one element, it will return true.
   */
  public static  boolean allEqual(@NonNull Iterable iterable) {
    return allEquivBy(iterable, Equiv. equal());
  }

  /**
   * Answers if all elements in the collection are the same object.
   * 
   * @param 
   * @param iterable
   *          non null. May be empty.
   * @return trueif all element are the same object.
   *         false otherwise. As a particular case of this rule, if
   *         this collection is empty or has only one element, it will return
   *         true.
   */
  public static  boolean allSame(@NonNull Iterable iterable) {
    return allEquivBy(iterable, Equiv. same());
  }

  /**
   * Tests if any of the elements of the given {@link Iterable} satisfy the
   * given predicate
   * 
   * @param 
   * @param iterable
   * @param predicate
   *          the predicate that will be used to evaluate each element
   * @return true if at least one element satisfies the given
   *         predicate, false otherwise. As a particular case of
   *         this rule, this method will return false for empty
   *         iterables, regardless of the predicate.
   */
  public static  boolean any(@NonNull Iterable iterable, Evaluable predicate) {
    for (A o : iterable)
      if (predicate.eval(o))
        return true;
    return false;
  }

  /**
   * Answers if the given {@link Iterable} is empty or not, that is, if its
   * iterator returns at least one element.
   * 
   * @param 
   *          the iterable element type
   * @param iterable
   * @return if the iterable is empty or not
   */
  public static  boolean isEmpty(@NonNull Iterable iterable) {
    return !iterable.iterator().hasNext();
  }

  /**
   * Answers if the given {@link Iterable} is empty or null
   * 
   * @param 
   *          the iterable element type
   * @param iterable
   * @return if the iterable is null or empty
   * @see #isEmpty(Iterable)
   */
  public static  boolean isNullOrEmpty(Iterable iterable) {
    return iterable == null || isEmpty(iterable);
  }

  /**
   * Answers if the given {@link Collection} is empty or null
   * 
   * @param 
   *          the collection element type
   * @param collection
   * @return if the collection is null or empty
   */
  public static  boolean isNullOrEmpty(Collection collection) {
    return collection == null || collection.isEmpty();
  }

  /**
   * Answers the size of the given iterable, that is, the number of
   * elements it retrieves
   * 
   * @param iterable
   * @return the number of elements in the given {@link Iterable}
   */
  public static int size(@NonNull Iterable iterable) {
    int size = 0;
    for (Iterator iter = iterable.iterator(); iter.hasNext(); iter.next())
      size++;
    return size;
  }

  /**
   * Test that the elements of both iterables are equal, and in the same order.
   * 
   * @param 
   * @param iterable1
   *          first iterable
   * @param iterable2
   *          second iterable
   * @return true if iterable1 has the same number of
   *         elements that iterable2, and each Tuple2 formed by
   *         elements of both iterables at same position are equal.
   *         false otherwise
   */
  public static  boolean equiv(@NonNull Iterable iterable1,
    @NonNull Iterable iterable2) {
    return equivBy(iterable1, iterable2, Equiv.equal().nullSafe());
  }

  /**
   * Test that the elements of of both iterables are equal, and in the same
   * order, using the given equalityTest for determining equality
   * of elements.
   * 
   * @param equivTest
   * @param equalityTest
   * @return true if iterable1 has the same number of
   *         elements that iterable2, and each Tuple2 formed by
   *         elements of both iterables at same position are equivalent using
   *         the given eqivTest. false otherwise
   */
  public static  boolean equivBy(@NonNull Iterable iterable1,
    @NonNull Iterable iterable2, Evaluable2 equivTest) {
    Iterator iter = iterable1.iterator();
    Iterator otherIter = iterable2.iterator();
    while (iter.hasNext()) {
      if (!otherIter.hasNext())
        return false;
      if (!equivTest.eval(iter.next(), otherIter.next()))
        return false;
    }
    return !otherIter.hasNext();
  }

  /*
   * Mapping
   */

  /**
   * Maps the given {@link Collection} into a new {@link List}, using the given
   * function
   * 
   * The resulting list contains contains the result of applying the given
   * function to each element retrieved from the original
   * iterable
   * 
   * @param 
   *          the element type of the given collection
   * @param 
   *          the element type of the resulting list
   * @param collection
   *          the source of the mapping.
   * @param function
   *          an {@link Applicable} applied to each element of the source
   *          collection.
   * @return a new, non null {@link List}. As a particular case, this method
   *         will return an empty list if the given collection is empty,
   *         regardless of the given {@link Applicable}
   */
  @NonNull
  public static  List map(@NonNull Collection collection,
    @NonNull Applicable function) {
    return collectInternal(//
      collection,
      function,
      new ArrayList(collection.size()));
  }

  /**
   * Maps the given {@link Iterable} into a new list, using the given
   * function.
   * 
   * The returned list contains contains the result of applying the given
   * function to each element retrieved from the original
   * iterable
   * 
   * 
   * @param 
   *          the element type of the given iterables
   * @param 
   *          the element type of the resulting list
   * @param iterable
   *          the source of the mapping.
   * @param function
   *          the function applied to each element of the source iterable.
   * @return a new, non null {@link List}. As a particular case, this method
   *         will return an empty list if the given iterable is empty
   */
  @NonNull
  public static  List map(@NonNull Iterable iterable,
    @NonNull Applicable function) {
    return collectInternal(iterable, function, new LinkedList());
  }

  /**
   * Maps the given iterable into a list of iterables using the
   * given function, and flattens the result, concatenating all the
   * resulting iterables into a {@link List}
   * 
   * @param 
   * @param 
   * @param iterable
   * @param function
   * @return a new {@link List}
   */
  @NonNull
  public static  List flatMap(@NonNull Iterable iterable,
    @NonNull Applicable> function) {
    LinkedList list = new LinkedList();

    for (A element : iterable)
      for (B applyedElement : function.apply(element))
        list.add(applyedElement);

    return list;
  }

  /*
   * Sorting and converting
   */

  /**
   * Sorts a the given iterable into a new list, using the given
   * comparator.
   * 
   * @param 
   * @param iterable
   *          the the collection.
   * @param comparator
   * @return a new list containing all the original colleciton elements, sorted
   *         using the given criteria, or an empty mutable list, if the original
   *         {@link Iterable} was empty.
   */
  @NonNull
  public static  List toSortedList(@NonNull Iterable iterable,
    @NonNull Comparator comparator) {
    List list = new LinkedList();
    addAllInternal(list, iterable);
    java.util.Collections.sort(list, comparator);
    return list;
  }

  /**
   * Sorts a given iterable using the given {@link Comparator} into
   * a new {@link SortedSet}
   * 
   * @param 
   * @param iterable
   *          the {@link Iterable} to sort
   * @param comparator
   * @return a sorted set containing the iterables elements sorted using the
   *         given comparator
   */
  @NonNull
  public static  SortedSet toSortedSet(@NonNull Iterable iterable,
    @NonNull Comparator comparator) {
    TreeSet sortedSet = new TreeSet(comparator);
    addAllInternal(sortedSet, iterable);
    return sortedSet;
  }

  /**
   * Sorts a given iterable using its natural ordering
   * 
   * @param 
   * @param iterable
   *          the {@link Iterable} to sort
   * @return a sorted set containing the iterables elements sorted using the
   *         given comparator
   */
  @NonNull
  public static > SortedSet toSortedSet(@NonNull Iterable iterable) {
    TreeSet sortedSet = new TreeSet();
    addAllInternal(sortedSet, iterable);
    return sortedSet;
  }

  /**
   * Converts the given elements into a {@link Set}.
   * 
   * @param 
   * @param elements
   * @return a new {@link Set} that contains the elements given without
   *         repetitions
   */
  public static  Set toSet(A... elements) {
    return toSet((Iterable) Arrays.asList(elements));
  }

  /**
   * Converts the given collection into a {@link Set}. If the collection is
   * already a set, it just returns it
   * 
   * @param 
   * @param collection
   * @return a new {@link Set} that contains all the elements from the given
   *         collection, or the given collection, if it is already a set
   */
  public static  Set toSet(Collection collection) {
    return collection instanceof Set ? (Set) collection : new HashSet(collection);
  }

  /**
   * Converts the given {@link Iterable} into a {@link Set}. If the
   * iterable is already a set, it just returns it
   * 
   * @param 
   * @param iterable
   * @return a new {@link Set} that contains all the elements from the given
   *         iterable, or the given iterable, if it is
   *         already a set
   */
  @NonNull
  public static  Set toSet(@NonNull Iterable iterable) {
    return ModifiableIterables.addAll(new HashSet(), iterable);
  }

  /**
   * Converts the given collection into a {@link List}. If the collection is
   * already a list, it just returns it
   * 
   * @param 
   * @param collection
   * @return a new {@link List} that contains all the elements from the given
   *         collection, or the given collection, if it is already a list
   */
  public static  List toList(@NonNull Collection collection) {
    return collection instanceof List ? (List) collection : new ArrayList(collection);
  }

  /**
   * Converts the given iterable into a {@link List}. If the iterable is already
   * a list, it just returns it
   * 
   * @param 
   * @param iterable
   * @return a new {@link List} that contains all the elements from the given
   *         iterable, or the given collection, if it is already a list
   */
  public static  List toList(Iterable iterable) {
    if (iterable instanceof List)
      return (List) iterable;
    LinkedList list = new LinkedList();
    ModifiableIterables.addAll(list, iterable);
    return list;
  }

  /* Partition */

  /**
   * Splits the given iterable by returning two {@link List}s, the first one
   * containing those elements that satisfy the given predicate, and the second
   * one containing those elements that do not satisfy it.
   * 
   * For example, the following code:
   * 
   * 
   * Iterables.partition(Arrays.asList(4, 8, 5, 20, 1), Predicate.greaterThan(5));
   * 
* * will return a Tuple2 equal to: * *
   * _(Arrays.asList(8, 20), Arrays.asList(4, 5, 1))
   * 
* * @param
* @param iterable * @param predicate * the {@link Evaluable} used to determine if an elements goes into * the first or second list * @return a Tuple2 of lists */ public static Tuple2, List> partition(@NonNull Iterable iterable, Evaluable predicate) { List first = new LinkedList(); List second = new LinkedList(); for (A element : iterable) if (predicate.eval(element)) first.add(element); else second.add(element); return _(first, second); } /** * Gets the zero-based, n-th element of the given * {@link Iterable}, according to its iteration order. * * @param * @param iterable * @param n * @return the n-th element * @throws IndexOutOfBoundsException * if n is greater or equal than the size of the * iterable */ public static A get(@NonNull Iterable iterable, int n) throws IndexOutOfBoundsException { A element = null; Iterator iter = iterable.iterator(); for (int i = 0; i <= n; i++) try { element = iter.next(); } catch (NoSuchElementException e) { throw new IndexOutOfBoundsException("At " + n); } return element; } /** * The zero-based index of a given element in the iterable when iterating over * it * * @param * @param iterable * @param element * @return the index of the element in the given iterable, or -1 if it is not * contained on it */ public static int indexOf(@NonNull Iterable iterable, A element) { int i = 0; for (Object o : iterable) { if (ObjectUtils.equals(element, o)) return i; i++; } return -1; } /** * If an element is before another when iterating through the given iterable. * * @param * @param iterable * @param previous * the element to test if exist in the iterable and is be before next * @param next * the element to test if exists in the iterable and is after * previous * @return true if both elements are contained by the given iterable, and * first element is before second one */ public static boolean isBefore(@NonNull Iterable iterable, A previous, A next) { if (ObjectUtils.equals(previous, next)) return false; boolean previousFound = false; for (A o : iterable) { if (!previousFound && ObjectUtils.equals(o, previous)) { previousFound = true; continue; } if (ObjectUtils.equals(o, next)) return previousFound; } return false; } /** * Returns a {@link List} formed by the result of applying the given * function to each Tuple2 of elements from the two iterables * given. If any if the {@link Iterable}s is shorter than the other one, the * remaining elements are discarded. *

* * @param * first iterable element type * @param * second iterable element type * @param * the resulting list element * @param iterable1 * @param iterable2 * @param function * the function to apply to each Tuple2 * @return a new list formed applying the given {@link Applicable2} to each * Tuple2 of element retrieved from the given iterables. The resulting * list size is the minimum of both iterables sizes. As a particular * case, if any of both iterables is empty, returns an empty list, * regardless of the given function * @see #zip(Iterable, Iterable) */ @NonNull public static List zip(@NonNull Iterable iterable1, @NonNull Iterable iterable2, Applicable2 function) { Iterator iter1 = iterable1.iterator(); Iterator iter2 = iterable2.iterator(); List result = new LinkedList(); while (iter1.hasNext() && iter2.hasNext()) result.add(function.apply(iter1.next(), iter2.next())); return result; } /** * Returns a {@link List} formed by Tuple2 of elements from the two iterables. * If any if the {@link Iterable}s is shorter than the other one, the * remaining elements are discarded. *

* For example, the following code: * *

   * Iterables.zip(Arrays.asList(10, 12, 14, 23), Arrays.asList(8, 7, 6))
   * 
* * will return a list equal to: * *
   * Arrays.asList(_(10, 8), _(12, 7), _(14, 6))
   * 
* *

* * @param
* first iterable element type * @param * second iterable element type * @param iterable1 * @param iterable2 * @return a new list formed by Tuple2 of element retrieved from the given * iterables. The resulting list size is the minimum of both iterables * sizes. As a particular case, if any of both iterables is empty, * returns an empty list. * @see #zip(Iterable, Iterable, Applicable2) */ @NonNull public static List> zip(@NonNull Iterable iterable1, @NonNull Iterable iterable2) { return zip(iterable1, iterable2, Tuples. toTuple2()); } /** * Answers the sum of the numeric elements of the given {@link Iterable}, * using the given {@link NumberType} to implement the addition. If the given * iterable is empty, it returns 0. * * For example, the following code: * *
   *  import static net.sf.staccatocommons.lang.number.NumberTypes.*;
   *  ...
   *  Iterables.sum(Arrays.asList(10, 60, 21), integer());
   * 
* * will produce the result (Integer) 91 * * @param
* @param iterable * @param type * @return fold(iterable, type.zero(), type.add()) */ @NonNull public static A sum(@NonNull Iterable iterable, @NonNull NumberType type) { return fold(iterable, type.zero(), type.add()); } /** * Answers the product of the numeric elements of the given {@link Iterable}, * using the given {@link NumberType} to implement the multiplication. If the * given iterable is empty, it returns 1. * * For example, the following code: * *
   *  import static net.sf.staccatocommons.lang.number.NumberTypes.*;
   *  ... 
   *  Iterables.product(Arrays.asList(2L, 4L, 8L, 3L), long_());
   * 
* * will produce the result (Long) 192L * * @param
* @param iterable * @param type * @return fold(iterable, type.one(), type.multiply()) */ @NonNull public static A product(@NonNull Iterable iterable, @NonNull NumberType type) { return fold(iterable, type.one(), type.multiply()); } /** * Answers the Cartesian product of the two given {@link Iterable}s. * * For example, the following code: * *
   * Iterables.cross((Iterable<Integer>) Arrays.asList(1, 2), Arrays.asList('a', 'b'));
   * 
* * Will produce a list equal to * *
   * Arrays.asList(_(1, 'a'), _(1, 'b'), _(2, 'a'), _(2, 'b'))
   * 
* * @param
* @param * @param iterable1 * @param iterable2 * @return a new List with the Cartesian product of both collections. */ @NonNull public static final List> cross(@NonNull Iterable iterable1, @NonNull Iterable iterable2) { return cross(iterable1, iterable2, new LinkedList()); } /** * Answers the Cartesian product of the two given {@link Collection}s. * * For example, the following code: * *
   * Iterables.cross(Arrays.asList(1, 2), Arrays.asList('a', 'b'));
   * 
* * Will produce a list equal to * *
   * Arrays.asList(_(1, 'a'), _(1, 'b'), _(2, 'a'), _(2, 'b'))
   * 
* * @param
* @param * @param collection1 * @param collection2 * @return a new List with the Cartesian product of both collections. */ @NonNull public static final List> cross(@NonNull Collection collection1, @NonNull Collection collection2) { return cross(collection1, collection2, new ArrayList(collection1.size() * collection2.size())); } @NonNull private static List> cross(@NonNull Iterable iterable1, @NonNull Iterable iterable2, @NonNull List> result) { for (A a : iterable1) for (B b : iterable2) { result.add(_(a, b)); } return result; } }