生成一个集合的所有可能的分组/子集组合,用尽每个项目

时间:2018-09-26 20:11:22

标签: javascript algorithm grouping subset combinations

更新:我完全低估了问题的严重性。至少在2018年和可预见的未来,这是不可能计算的!


给予

SET = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

SUBSET_SIZES = [3, 2, 2]

我想找到SET确定的SUBSET_SIZES的所有可能分组/子集组合,同时用完原始集中的所有项目。

以上输入的结果如下:

[['a', 'b', 'c'], ['d', 'e'], ['f', 'g']],
[['a', 'b', 'c'], ['d', 'f'], ['e', 'g']],
[['a', 'b', 'c'], ['d', 'g'], ['e', 'f']],
[['a', 'b', 'c'], ['e', 'f'], ['d', 'g']],
[['a', 'b', 'c'], ['e', 'g'], ['d', 'f']],
[['a', 'b', 'c'], ['f', 'g'], ['d', 'e']],
[['a', 'b', 'd'], ['c', 'e'], ['f', 'g']],
[['a', 'b', 'd'], ['c', 'f'], ['e', 'g']],
[['a', 'b', 'd'], ['c', 'g'], ['e', 'f']],
[['a', 'b', 'd'], ['e', 'f'], ['c', 'g']],
... and 200 more ...

我的实际数据集将更大(〜50个项目),并且子集大小每个将在4到6个项目之间变化,因此我正在寻找一种相当有效的方式来查找组合。但是,我认为需要2-3分钟才能完成较大的数据集。

我想在JavaScript中实现它,因此,如果您已经知道可以完成此工作的JavaScript代码,那就太好了。如果是ES6生成器代码,那就更好了!我用完了谷歌搜索功能。

下面是带有几个Jasmine测试的代码段:

function getPossibleGroupCombinations() {
  return [];
}

describe('getPossibleGroupCombinations', () => {
  it('works with a tiny set', () => {
    const possibleCombos = getPossibleGroupCombinations(['a', 'b', 'c'], [2, 1]);

    expect(possibleCombos).toEqual([
      [['a', 'b'], ['c']],
      [['a', 'c'], ['b']],
      [['b', 'c'], ['a']],
    ]);
  });
  
  it('works with a big set', () => {
    const possibleCombos = getPossibleGroupCombinations(
      ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
      [3, 2, 2]
    );

    expect(possibleCombos).toEqual([
      [['a', 'b', 'c'], ['d', 'e'], ['f', 'g']],
      [['a', 'b', 'c'], ['d', 'f'], ['e', 'g']],
      [['a', 'b', 'c'], ['d', 'g'], ['e', 'f']],
      [['a', 'b', 'c'], ['e', 'f'], ['d', 'g']],
      [['a', 'b', 'c'], ['e', 'g'], ['d', 'f']],
      [['a', 'b', 'c'], ['f', 'g'], ['d', 'e']],
      [['a', 'b', 'd'], ['c', 'e'], ['f', 'g']],
      [['a', 'b', 'd'], ['c', 'f'], ['e', 'g']],
      [['a', 'b', 'd'], ['c', 'g'], ['e', 'f']],
      [['a', 'b', 'd'], ['e', 'f'], ['c', 'g']],
      [['a', 'b', 'd'], ['e', 'g'], ['c', 'f']],
      [['a', 'b', 'd'], ['f', 'g'], ['c', 'e']],
      [['a', 'b', 'e'], ['c', 'd'], ['f', 'g']],
      [['a', 'b', 'e'], ['c', 'f'], ['d', 'g']],
      [['a', 'b', 'e'], ['c', 'g'], ['d', 'f']],
      [['a', 'b', 'e'], ['d', 'f'], ['c', 'g']],
      [['a', 'b', 'e'], ['d', 'g'], ['c', 'f']],
      [['a', 'b', 'e'], ['f', 'g'], ['c', 'd']],
      [['a', 'b', 'f'], ['c', 'd'], ['e', 'g']],
      [['a', 'b', 'f'], ['c', 'e'], ['d', 'g']],
      [['a', 'b', 'f'], ['c', 'g'], ['d', 'e']],
      [['a', 'b', 'f'], ['d', 'e'], ['c', 'g']],
      [['a', 'b', 'f'], ['d', 'g'], ['c', 'e']],
      [['a', 'b', 'f'], ['e', 'g'], ['c', 'd']],
      [['a', 'b', 'g'], ['c', 'd'], ['e', 'f']],
      [['a', 'b', 'g'], ['c', 'e'], ['d', 'f']],
      [['a', 'b', 'g'], ['c', 'f'], ['d', 'e']],
      [['a', 'b', 'g'], ['d', 'e'], ['c', 'f']],
      [['a', 'b', 'g'], ['d', 'f'], ['c', 'e']],
      [['a', 'b', 'g'], ['e', 'f'], ['c', 'd']],
      [['a', 'c', 'd'], ['b', 'e'], ['f', 'g']],
      [['a', 'c', 'd'], ['b', 'f'], ['e', 'g']],
      [['a', 'c', 'd'], ['b', 'g'], ['e', 'f']],
      [['a', 'c', 'd'], ['e', 'f'], ['b', 'g']],
      [['a', 'c', 'd'], ['e', 'g'], ['b', 'f']],
      [['a', 'c', 'd'], ['f', 'g'], ['b', 'e']],
      [['a', 'c', 'e'], ['b', 'd'], ['f', 'g']],
      [['a', 'c', 'e'], ['b', 'f'], ['d', 'g']],
      [['a', 'c', 'e'], ['b', 'g'], ['d', 'f']],
      [['a', 'c', 'e'], ['d', 'f'], ['b', 'g']],
      [['a', 'c', 'e'], ['d', 'g'], ['b', 'f']],
      [['a', 'c', 'e'], ['f', 'g'], ['b', 'd']],
      [['a', 'c', 'f'], ['b', 'd'], ['e', 'g']],
      [['a', 'c', 'f'], ['b', 'e'], ['d', 'g']],
      [['a', 'c', 'f'], ['b', 'g'], ['d', 'e']],
      [['a', 'c', 'f'], ['d', 'e'], ['b', 'g']],
      [['a', 'c', 'f'], ['d', 'g'], ['b', 'e']],
      [['a', 'c', 'f'], ['e', 'g'], ['b', 'd']],
      [['a', 'c', 'g'], ['b', 'd'], ['e', 'f']],
      [['a', 'c', 'g'], ['b', 'e'], ['d', 'f']],
      [['a', 'c', 'g'], ['b', 'f'], ['d', 'e']],
      [['a', 'c', 'g'], ['d', 'e'], ['b', 'f']],
      [['a', 'c', 'g'], ['d', 'f'], ['b', 'e']],
      [['a', 'c', 'g'], ['e', 'f'], ['b', 'd']],
      [['a', 'd', 'e'], ['b', 'c'], ['f', 'g']],
      [['a', 'd', 'e'], ['b', 'f'], ['c', 'g']],
      [['a', 'd', 'e'], ['b', 'g'], ['c', 'f']],
      [['a', 'd', 'e'], ['c', 'f'], ['b', 'g']],
      [['a', 'd', 'e'], ['c', 'g'], ['b', 'f']],
      [['a', 'd', 'e'], ['f', 'g'], ['b', 'c']],
      [['a', 'd', 'f'], ['b', 'c'], ['e', 'g']],
      [['a', 'd', 'f'], ['b', 'e'], ['c', 'g']],
      [['a', 'd', 'f'], ['b', 'g'], ['c', 'e']],
      [['a', 'd', 'f'], ['c', 'e'], ['b', 'g']],
      [['a', 'd', 'f'], ['c', 'g'], ['b', 'e']],
      [['a', 'd', 'f'], ['e', 'g'], ['b', 'c']],
      [['a', 'd', 'g'], ['b', 'c'], ['e', 'f']],
      [['a', 'd', 'g'], ['b', 'e'], ['c', 'f']],
      [['a', 'd', 'g'], ['b', 'f'], ['c', 'e']],
      [['a', 'd', 'g'], ['c', 'e'], ['b', 'f']],
      [['a', 'd', 'g'], ['c', 'f'], ['b', 'e']],
      [['a', 'd', 'g'], ['e', 'f'], ['b', 'c']],
      [['a', 'e', 'f'], ['b', 'c'], ['d', 'g']],
      [['a', 'e', 'f'], ['b', 'd'], ['c', 'g']],
      [['a', 'e', 'f'], ['b', 'g'], ['c', 'd']],
      [['a', 'e', 'f'], ['c', 'd'], ['b', 'g']],
      [['a', 'e', 'f'], ['c', 'g'], ['b', 'd']],
      [['a', 'e', 'f'], ['d', 'g'], ['b', 'c']],
      [['a', 'e', 'g'], ['b', 'c'], ['d', 'f']],
      [['a', 'e', 'g'], ['b', 'd'], ['c', 'f']],
      [['a', 'e', 'g'], ['b', 'f'], ['c', 'd']],
      [['a', 'e', 'g'], ['c', 'd'], ['b', 'f']],
      [['a', 'e', 'g'], ['c', 'f'], ['b', 'd']],
      [['a', 'e', 'g'], ['d', 'f'], ['b', 'c']],
      [['a', 'f', 'g'], ['b', 'c'], ['d', 'e']],
      [['a', 'f', 'g'], ['b', 'd'], ['c', 'e']],
      [['a', 'f', 'g'], ['b', 'e'], ['c', 'd']],
      [['a', 'f', 'g'], ['c', 'd'], ['b', 'e']],
      [['a', 'f', 'g'], ['c', 'e'], ['b', 'd']],
      [['a', 'f', 'g'], ['d', 'e'], ['b', 'c']],
      [['b', 'c', 'd'], ['a', 'e'], ['f', 'g']],
      [['b', 'c', 'd'], ['a', 'f'], ['e', 'g']],
      [['b', 'c', 'd'], ['a', 'g'], ['e', 'f']],
      [['b', 'c', 'd'], ['e', 'f'], ['a', 'g']],
      [['b', 'c', 'd'], ['e', 'g'], ['a', 'f']],
      [['b', 'c', 'd'], ['f', 'g'], ['a', 'e']],
      [['b', 'c', 'e'], ['a', 'd'], ['f', 'g']],
      [['b', 'c', 'e'], ['a', 'f'], ['d', 'g']],
      [['b', 'c', 'e'], ['a', 'g'], ['d', 'f']],
      [['b', 'c', 'e'], ['d', 'f'], ['a', 'g']],
      [['b', 'c', 'e'], ['d', 'g'], ['a', 'f']],
      [['b', 'c', 'e'], ['f', 'g'], ['a', 'd']],
      [['b', 'c', 'f'], ['a', 'd'], ['e', 'g']],
      [['b', 'c', 'f'], ['a', 'e'], ['d', 'g']],
      [['b', 'c', 'f'], ['a', 'g'], ['d', 'e']],
      [['b', 'c', 'f'], ['d', 'e'], ['a', 'g']],
      [['b', 'c', 'f'], ['d', 'g'], ['a', 'e']],
      [['b', 'c', 'f'], ['e', 'g'], ['a', 'd']],
      [['b', 'c', 'g'], ['a', 'd'], ['e', 'f']],
      [['b', 'c', 'g'], ['a', 'e'], ['d', 'f']],
      [['b', 'c', 'g'], ['a', 'f'], ['d', 'e']],
      [['b', 'c', 'g'], ['d', 'e'], ['a', 'f']],
      [['b', 'c', 'g'], ['d', 'f'], ['a', 'e']],
      [['b', 'c', 'g'], ['e', 'f'], ['a', 'd']],
      [['b', 'd', 'e'], ['a', 'c'], ['f', 'g']],
      [['b', 'd', 'e'], ['a', 'f'], ['c', 'g']],
      [['b', 'd', 'e'], ['a', 'g'], ['c', 'f']],
      [['b', 'd', 'e'], ['c', 'f'], ['a', 'g']],
      [['b', 'd', 'e'], ['c', 'g'], ['a', 'f']],
      [['b', 'd', 'e'], ['f', 'g'], ['a', 'c']],
      [['b', 'd', 'f'], ['a', 'c'], ['e', 'g']],
      [['b', 'd', 'f'], ['a', 'e'], ['c', 'g']],
      [['b', 'd', 'f'], ['a', 'g'], ['c', 'e']],
      [['b', 'd', 'f'], ['c', 'e'], ['a', 'g']],
      [['b', 'd', 'f'], ['c', 'g'], ['a', 'e']],
      [['b', 'd', 'f'], ['e', 'g'], ['a', 'c']],
      [['b', 'd', 'g'], ['a', 'c'], ['e', 'f']],
      [['b', 'd', 'g'], ['a', 'e'], ['c', 'f']],
      [['b', 'd', 'g'], ['a', 'f'], ['c', 'e']],
      [['b', 'd', 'g'], ['c', 'e'], ['a', 'f']],
      [['b', 'd', 'g'], ['c', 'f'], ['a', 'e']],
      [['b', 'd', 'g'], ['e', 'f'], ['a', 'c']],
      [['b', 'e', 'f'], ['a', 'c'], ['d', 'g']],
      [['b', 'e', 'f'], ['a', 'd'], ['c', 'g']],
      [['b', 'e', 'f'], ['a', 'g'], ['c', 'd']],
      [['b', 'e', 'f'], ['c', 'd'], ['a', 'g']],
      [['b', 'e', 'f'], ['c', 'g'], ['a', 'd']],
      [['b', 'e', 'f'], ['d', 'g'], ['a', 'c']],
      [['b', 'e', 'g'], ['a', 'c'], ['d', 'f']],
      [['b', 'e', 'g'], ['a', 'd'], ['c', 'f']],
      [['b', 'e', 'g'], ['a', 'f'], ['c', 'd']],
      [['b', 'e', 'g'], ['c', 'd'], ['a', 'f']],
      [['b', 'e', 'g'], ['c', 'f'], ['a', 'd']],
      [['b', 'e', 'g'], ['d', 'f'], ['a', 'c']],
      [['b', 'f', 'g'], ['a', 'c'], ['d', 'e']],
      [['b', 'f', 'g'], ['a', 'd'], ['c', 'e']],
      [['b', 'f', 'g'], ['a', 'e'], ['c', 'd']],
      [['b', 'f', 'g'], ['c', 'd'], ['a', 'e']],
      [['b', 'f', 'g'], ['c', 'e'], ['a', 'd']],
      [['b', 'f', 'g'], ['d', 'e'], ['a', 'c']],
      [['c', 'd', 'e'], ['a', 'b'], ['f', 'g']],
      [['c', 'd', 'e'], ['a', 'f'], ['b', 'g']],
      [['c', 'd', 'e'], ['a', 'g'], ['b', 'f']],
      [['c', 'd', 'e'], ['b', 'f'], ['a', 'g']],
      [['c', 'd', 'e'], ['b', 'g'], ['a', 'f']],
      [['c', 'd', 'e'], ['f', 'g'], ['a', 'b']],
      [['c', 'd', 'f'], ['a', 'b'], ['e', 'g']],
      [['c', 'd', 'f'], ['a', 'e'], ['b', 'g']],
      [['c', 'd', 'f'], ['a', 'g'], ['b', 'e']],
      [['c', 'd', 'f'], ['b', 'e'], ['a', 'g']],
      [['c', 'd', 'f'], ['b', 'g'], ['a', 'e']],
      [['c', 'd', 'f'], ['e', 'g'], ['a', 'b']],
      [['c', 'd', 'g'], ['a', 'b'], ['e', 'f']],
      [['c', 'd', 'g'], ['a', 'e'], ['b', 'f']],
      [['c', 'd', 'g'], ['a', 'f'], ['b', 'e']],
      [['c', 'd', 'g'], ['b', 'e'], ['a', 'f']],
      [['c', 'd', 'g'], ['b', 'f'], ['a', 'e']],
      [['c', 'd', 'g'], ['e', 'f'], ['a', 'b']],
      [['c', 'e', 'f'], ['a', 'b'], ['d', 'g']],
      [['c', 'e', 'f'], ['a', 'd'], ['b', 'g']],
      [['c', 'e', 'f'], ['a', 'g'], ['b', 'd']],
      [['c', 'e', 'f'], ['b', 'd'], ['a', 'g']],
      [['c', 'e', 'f'], ['b', 'g'], ['a', 'd']],
      [['c', 'e', 'f'], ['d', 'g'], ['a', 'b']],
      [['c', 'e', 'g'], ['a', 'b'], ['d', 'f']],
      [['c', 'e', 'g'], ['a', 'd'], ['b', 'f']],
      [['c', 'e', 'g'], ['a', 'f'], ['b', 'd']],
      [['c', 'e', 'g'], ['b', 'd'], ['a', 'f']],
      [['c', 'e', 'g'], ['b', 'f'], ['a', 'd']],
      [['c', 'e', 'g'], ['d', 'f'], ['a', 'b']],
      [['c', 'f', 'g'], ['a', 'b'], ['d', 'e']],
      [['c', 'f', 'g'], ['a', 'd'], ['b', 'e']],
      [['c', 'f', 'g'], ['a', 'e'], ['b', 'd']],
      [['c', 'f', 'g'], ['b', 'd'], ['a', 'e']],
      [['c', 'f', 'g'], ['b', 'e'], ['a', 'd']],
      [['c', 'f', 'g'], ['d', 'e'], ['a', 'b']],
      [['d', 'e', 'f'], ['a', 'b'], ['c', 'g']],
      [['d', 'e', 'f'], ['a', 'c'], ['b', 'g']],
      [['d', 'e', 'f'], ['a', 'g'], ['b', 'c']],
      [['d', 'e', 'f'], ['b', 'c'], ['a', 'g']],
      [['d', 'e', 'f'], ['b', 'g'], ['a', 'c']],
      [['d', 'e', 'f'], ['c', 'g'], ['a', 'b']],
      [['d', 'e', 'g'], ['a', 'b'], ['c', 'f']],
      [['d', 'e', 'g'], ['a', 'c'], ['b', 'f']],
      [['d', 'e', 'g'], ['a', 'f'], ['b', 'c']],
      [['d', 'e', 'g'], ['b', 'c'], ['a', 'f']],
      [['d', 'e', 'g'], ['b', 'f'], ['a', 'c']],
      [['d', 'e', 'g'], ['c', 'f'], ['a', 'b']],
      [['d', 'f', 'g'], ['a', 'b'], ['c', 'e']],
      [['d', 'f', 'g'], ['a', 'c'], ['b', 'e']],
      [['d', 'f', 'g'], ['a', 'e'], ['b', 'c']],
      [['d', 'f', 'g'], ['b', 'c'], ['a', 'e']],
      [['d', 'f', 'g'], ['b', 'e'], ['a', 'c']],
      [['d', 'f', 'g'], ['c', 'e'], ['a', 'b']],
      [['e', 'f', 'g'], ['a', 'b'], ['c', 'd']],
      [['e', 'f', 'g'], ['a', 'c'], ['b', 'd']],
      [['e', 'f', 'g'], ['a', 'd'], ['b', 'c']],
      [['e', 'f', 'g'], ['b', 'c'], ['a', 'd']],
      [['e', 'f', 'g'], ['b', 'd'], ['a', 'c']],
      [['e', 'f', 'g'], ['c', 'd'], ['a', 'b']],
    ]);
  });
});


// load jasmine htmlReporter
(function() {
  var env = jasmine.getEnv();
  env.addReporter(new jasmine.HtmlReporter());
  env.execute();
}());
<link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
<script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>

2 个答案:

答案 0 :(得分:0)

概念证明...

您可以使用数组长度的阶乘作为获取所需排列的帮助。

基本上,该算法会计算数组的索引,并在其上重新组合结果。

子集数组只是表面上的。

这种方法很慢,因为它会生成第n th 个排列。一种更快的方法可能是继续进行最后的修改,然后继续进行下一次修改。

function getN(n, array, subsets) {
    var f,
        l = array.length,
        indices = [],
        temp;

    array = array.slice();
    while (l--) {
        f = factorial(l);
        indices.push(Math.floor(n / f));
        n %= f;
    }
    temp = indices.map(i => array.splice(i, 1)[0]);
    return subsets
        ? subsets.map((i => l => temp.slice(i, i += l))(0))
        : temp;


}

function factorial(num) {
    var result = 1;
    while (num) {
        result *= num;
        num--;
    }
    return result;
}

var i, l,
    array = ['a', 'b', 'c', 'd', 'e', 'f', 'g'],
    subsets = [3, 2, 2],
    pre = document.getElementById('out');

for (i = 0, l = factorial(array.length); i < l; i++) {
    pre.innerHTML += i.toString().padStart(4) +': ' + JSON.stringify(getN(i, array, subsets)) + '\n';
}
<pre id="out"></pre>

答案 1 :(得分:0)

如果要合并所有可能的组合值(笛卡尔积),可以使用lodash框架的product()函数:

var allCombinations = _.product(
       /* RequestState    */[RequestState.Completed, RequestState.Failed, RequestState.PartiallyCompleted, RequestState.Canceled, RequestState.Available, RequestState.InProgress],
       /* ApprovalState   */[ApprovalState.Denied, ApprovalState.WaitingForApproval],
       /* hasAccessToCase */[true, false],
       /* IsRequestOwner  */[true, false],
       /* categoryId*/      [1, 2, 3],
    );

在上面的示例中,这将导致6x2x2x2x3 = 144个组合的数组

然后可以使用数组forEach遍历所有组合:

allCombinations.forEach(([requestState, approvalState, hasAcccesToCase,  isRequestOwner, categoryId]) => {

     (...)

});