生成一组对象的所有组合

时间:2013-01-25 12:42:43

标签: java object combinations powerset

我在这里遇到一个问题,我需要生成所有可能的对象组合,并将它们存储在列表中以供日后分析..

互联网上的搜索包含许多不符合存储组合要求的算法。 大多数常见的搜索只是通过打印它们来生成组合列表,而其他搜索只处理字符串而不是对象。

某些算法使用位来表示不同的组合,但此解决方案仅限制为最多32个对象,这不够好。

总的来说,我正在寻找一种算法,我可以生成所有可能的组合(电源组),处理对象(超过32个),而不仅限于打印组合,而是将这些组合存储在数组列表。

1 个答案:

答案 0 :(得分:1)

您是否考虑过这样的想法,而不是一次性生成所有组合到一个可能巨大且无法管理的数组中,您为数组中的每个条目编写一个生成器,从而创建一种访问条目的伪数组创建条目在飞行中。

这是我在另一个接近问题的问题中发布的enum迭代器的代码。虽然它实现了Iterator,但在内部它通过解码索引并从动态索引的位模式中选择组合来生成每个组合(请参阅private Enum[] get(int x)方法)。如果您愿意,应该可以将其扩展为使用BigInteger甚至byte[]作为索引。

public class EnumIterator implements Iterator<Enum[]> {
  // The enum classes
  private final Class<? extends Enum>[] enums;
  // The pseudo-position in the list.
  private int i = 0;
  // The total entries in the list.
  private final int N;

  // Construct from classes.
  private EnumIterator(Class<? extends Enum>... enums) {
    // Grab the enums.
    this.enums = enums;
    // Work out the Max as the product of all sets of constants.
    int max = 1;
    for (int n = 0; n < enums.length; n++) {
      max *= enums[n].getEnumConstants().length;
    }
    N = max;
  }

  // Get that one from the possibles.
  private Enum[] get(int x) {
    // Make new array.
    Enum[] next = new Enum[enums.length];
    // Fill it with the ith entry.
    for (int j = next.length - 1; j >= 0; j--) {
      Enum[] e = enums[j].getEnumConstants();
      // Pick the right one from it.
      next[j] = e[x % e.length];
      // Fold out that enum.
      x /= e.length;
    }
    return next;
  }

  @Override
  public boolean hasNext() {
    return i < N;
  }

  @Override
  public Enum[] next() {
    if (hasNext()) {
      return get(i++);
    } else {
      throw new NoSuchElementException();
    }
  }

  @Override
  public void remove() {
    throw new UnsupportedOperationException("Not supported.");
  }

  enum ABC {
    A, B, C;
  }

  enum XY {
    X, Y;
  }

  enum IJ {
    I, J;
  }

  enum OneTwoThree {
    ONE, TWO, THREE
  }

  private static void test() {
    // Also works - but constructing from classes is cleaner.
    //Iterator<Enum[]> i = new EnumIterator(ABC.values(), XY.values(), IJ.values());
    System.out.println("ABC x XY x IJ");
    for (Enum[] e : Iterables.in(new EnumIterator(ABC.class, XY.class, IJ.class))) {
      System.out.println(Arrays.toString(e));
    }
    System.out.println("ABC");
    for (Enum[] e : Iterables.in(new EnumIterator(ABC.class))) {
      System.out.println(Arrays.toString(e));
    }
    System.out.println("ABC x OneTwoThree");
    for (Enum[] e : Iterables.in(new EnumIterator(ABC.class, OneTwoThree.class))) {
      System.out.println(Arrays.toString(e));
    }
    System.out.println("MT");
    for (Enum[] e : Iterables.in(new EnumIterator())) {
      System.out.println(Arrays.toString(e));
    }
  }

  public static void main(String args[]) {
    test();
  }
}