I need to construct the power sets of a set, lazily, by smallest size first. I have a working class+algorithm (see below), but I feel like perhaps it's crazy, because it seems waaaay too elaborate.
I am looking for alternatives; any suggestions? If some of the collections look unfamiliar, they are from the Google Collections library, but the naming convention should make their properties pretty self-explanatory.
import java.util.*;
import com.google.common.base.Function;
import com.google.common.collect.*;
public class PowerSetBuilder<Type> extends ForwardingMap<Type,PowerSetBuilder<Type>> {
private final ImmutableMap<Type,PowerSetBuilder<Type>> delegate;
@Override protected ImmutableMap<Type, PowerSetBuilder<Type>> delegate() { return delegate; }
private final int depth;
public PowerSetBuilder(ImmutableSet<Type> set) {
depth = set.size();
ImmutableMap.Builder<Type, PowerSetBuilder<Type>> builder = ImmutableMap.builder();
Set<Type> local = Sets.newLinkedHashSet(set);
Type key;
for (Iterator<Type> iter = local.iterator(); iter.hasNext(); ) {
key = iter.next();
iter.remove();
builder.put(key, new PowerSetBuilder<Type>(ImmutableSet.copyOf(local)));
}
delegate = builder.build();
}
private ImmutableSetMultimap<Integer,ImmutableSet<Type>> powerSets;
private ImmutableSet<ImmutableSet<Type>> powerSet;
public ImmutableSet<ImmutableSet<Type>> powerSet() {
if (powerSet == null) powerSet = getAllPowers();
return powerSet;
}
private ImmutableSet<ImmutableSet<Type>> getAllPowers() {
ImmutableSet.Builder<ImmutableSet<Type>> builder = ImmutableSet.builder();
for (int i=0;i<=depth;i++) builder.addAll(setsOfSize(i));
return builder.build();
}
public ImmutableSet<ImmutableSet<Type>> setsOfSize(int size) {
if (powerSets == null) {
powerSets = ImmutableSetMultimap.of();
}
if (!powerSets.containsKey(size)) {
ImmutableSetMultimap.Builder<Integer, ImmutableSet<Type>> builder = ImmutableSetMultimap.builder();
builder.putAll(powerSets);
builder.putAll(size, makeSetSize(size));
powerSets = builder.build();
}
return powerSets.get(size);
}
private ImmutableSet<ImmutableSet<Type>> makeSetSize(int size) {
if (size == 0) return ImmutableSet.of(ImmutableSet.<Type>of());
if (size == 1) return ImmutableSet.copyOf(Iterables.transform(keySet(), singleton));
ImmutableSet.Builder<ImmutableSet<Type>> builder = ImmutableSet.builder();
int check = 0;
Type key;
for (Iterator<Type> keyIter = keySet().iterator(); keyIter.hasNext() && check < depth+1-size; check++) {
key = keyIter.next();
builder.addAll(Iterables.transform(get(key).makeSetSize(size-1), prepend(key)));
}
return builder.build();
}
private Function<Type,ImmutableSet<Type>> singleton = new Function<Type,ImmutableSet<Type>>() {
@Override public ImmutableSet<Type> apply(Type element) { return ImmutableSet.of(element); }
};
private Function<ImmutableSet<Type>,ImmutableSet<Type>> prepend(final Type add) {
return new Function<ImmutableSet<Type>,ImmutableSet<Type>>(){
@Override public ImmutableSet<Type> apply(ImmutableSet<Type> to) {
return ImmutableSet.<Type>builder()
.add(add)
.addAll(to)
.build();
}};
}
}