package org.tenidwa.collections.utils; import com.google.common.collect.ForwardingSet; import com.google.common.collect.ImmutableSet; import java.util.LinkedHashSet; import java.util.Set; import java.util.function.BiFunction; /** * <a href="http://en.wikipedia.org/wiki/Cartesian_product">Cartesian * product</a> of two sets. * <p/> * Computes all possible pairs where the first element is from set A, and the * second element is from set B, and maps those pairs to whatever you need. * @author Georgy Vlasov (suseika@tendiwa.org) * @version $Id$ * @since 0.5.0 */ public final class CartesianProduct<A, B, R> extends ForwardingSet<R> { /** * First multiplier. */ private final transient Set<A> one; /** * Second multiplier. */ private final transient Set<B> two; /** * Function to produce the results from pairs. */ private final transient BiFunction<A, B, R> function; /** * Saved result. */ private transient Set<R> result; /** * Ctor. * @param one First multiplier * @param two Second multiplier */ public CartesianProduct( final Set<A> one, final Set<B> two, final BiFunction<A, B, R> function ) { this.one = one; this.two = two; this.function = function; } @Override protected Set<R> delegate() { if (this.result == null) { this.result = this.multiplication(); } return this.result; } /** * Creates Cartesian product of two lists. */ private Set<R> multiplication() { final Set<R> answer = new LinkedHashSet<>( this.one.size() * this.two.size() ); for (final A left : this.one) { for (final B right : this.two) { final R element = this.function.apply(left, right); if (answer.contains(element)) { throw new IllegalStateException( String.format( "Cartesian product result contains duplicated element %s", element ) ); } answer.add(element); } } return ImmutableSet.copyOf(answer); } }