package org.hivedb.util;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.hivedb.util.functional.Atom;
import org.hivedb.util.functional.Filter;
import org.hivedb.util.functional.Predicate;
import org.hivedb.util.functional.Transform;
import org.hivedb.util.functional.Unary;
/// <summary>
/// Performs combination operations on a collection with unique elements. All collections are converted to Set Ts to do computations.
/// The basic equation for the number of combinations is
/// n! / (n-r)! * r where n is the number of items in the list and r is the number in each result set
/// When computing combinations of all sizes the equation is thus
/// Sum r=[1,n] n! / ((n-r)! * r!)
/// </summary>
public class Combiner
{
/// <summary>
/// Generate all permutations of the given collection up to the given set size
/// </summary>
/// <param name="collection"</param>
/// <returns></returns>
public static<T> Collection<Set<T>> generateSets(Collection<T> collection, int maxSetSize)
{
return generateSets(new HashSet<T>(collection), maxSetSize);
}
public static<T> Collection<Set<T>> generateSets(Set<T> set, final int maxSetSize)
{
if (set.size() == 0)
return Collections.emptyList();
if (set.size() == 1)
return Collections.singletonList(set);
final T first = Atom.getFirstOrThrow(set);
// Create all sets without the first item
Collection<T> rest = Atom.getRestOrThrow(set);
Collection<Set<T>> results = generateSets(rest, maxSetSize);
// Combine three sets of sets
return Transform.flatten((Collection<Set<T>>)
Transform.map(new Unary<Set<T>, Set<T>>() { // add first item to all previously generated sets
public Set<T> f(Set<T> set) {
Set newSet = new HashSet((Set)set);
newSet.add(first);
return newSet;
}}, Filter.grep(new Predicate<Set<T>>() {
public boolean f(Set<T> set) {
return set.size() < maxSetSize;
}}, results)),
results, // previously generated sets
Collections.singletonList(Collections.singleton(first))); // the first item in a set alone
}
}