【问题标题】:Find all combinations of elements in an array查找数组中元素的所有组合
【发布时间】:2014-03-31 20:05:38
【问题描述】:

我要解决的问题是我想生成一个数组,它代表源数组中元素的所有组合。

给定 2 个项目的输入,有 4 种组合(这里表示为二进制)

第 1 组 | 0 | 1 | 0 | 1
第 2 组 | 0 | 0 | 1 | 1
--------------------------
&结果 | 0 | 1 | 2 | 3

这可以概括,所以组合的数量是 2(组数)(所以 3 个组有 8 个组合,4 个有 16 个等等)。

所以问题是;给定一个javascript数组:

var groups = [
{
    name:"group1",
    bit: 1
},
{
    name:"group2",
    bit: 2
},
{
    name:"group3",
    bit: 4
}];

我需要生成一个数组,其中索引表示 bit 属性的与,并且数组的值是任意的(进一步计算 - 不相关),所以我们只需将其设为组名数组(出于这个问题的目的)。这个结果是可取的:

var result = [
    {groups: []}, //0 
    {groups: ["group1"]}, //1
    {groups: ["group2"]},  //2
    {groups: ["group1","group2"]}, //3
    {groups: ["group3"]}, //4
    {groups: ["group1","group3"]}, //5
    {groups: ["group2","group3"]}, //6
    {groups: ["group1","group2","group3"]} //7
]

您可以在那里的 cmets 中看到,数组中的每个索引都表示与原始的 bit 属性相匹配的行为。

我已经准备了一个jsfiddle,其中包含输入和所需的输出,如果它有助于回答问题。


This is my current solution,基于mellamokb's answer,但以我喜欢的风格重新编写。我希望有一个更优雅的解决方案,因为这对数组有很多不必要的迭代。有更好的解决方案吗?

var resultCount = Math.pow(2,groups.length);
var result = [];
for(var i=0;i<resultCount;i++){
    result.push({
        groups: $.map(groups, function(e,idx){ 
           return  ((i & Math.pow(2,idx)) != 0)
               ? e.name
               : null
        })
    });
}

【问题讨论】:

  • 解决方案是否需要担心性能?您预计拥有的最大输入组数量是多少?
  • 实践中最大的组数是 4(所以 16 个组合)。实际上,我会谨慎行事,并期望可能有 6 个。
  • 您能解释一下哪些迭代是不必要的吗?如果您想列举所有可能性,我看不出如何将问题减少到小于 (length^3) 次迭代。
  • @tau - 唯一不必要的组合是相反的组合。所有组合都是必需的。

标签: javascript arrays combinations


【解决方案1】:

这是一个相对有效的解决方案,通过索引构建数组:

var result = [];
var resultCount = Math.pow(2, groups.length);

for (var i = 0; i < resultCount; i++) {
    result[i] = { groups: [] };
    for (var g = 0; g < groups.length; g++) {
        if (i & groups[g].bit) result[i].groups.push(groups[g].name);
    }
}

演示:http://jsfiddle.net/7ZsHL/9/

【讨论】:

  • 这看起来很不错,但是您可以用 var resultCount = Math.pow(2,groups.length) 替换组上的迭代以计算 resultCount
  • @Jamiec:好主意。我一直对使用Math.pow 有点紧张,因为它是一个浮点计算。
【解决方案2】:

我认为你可以做到这一点,而不必存储比特,什么不是。

var groups = [
    "group1",
    "group2",
    "group3",
    "group4"
];

var output = [];
for (var i = 0; i < Math.pow(2, groups.length); i++) {
    var arr = [];
    output.push(arr);
    for (var j = 0; j < groups.length; j++) {
        if (i & (Math.pow(2, j))) {
            arr.push(groups[j]);
        } else {
            arr.push(0);
        }
    }
}

【讨论】:

  • 您可能希望将Math.pow(2, groups.length) 存储到一个变量中,否则每次迭代都会重新计算它。
【解决方案3】:

我喜欢其他人的做法,但在这种情况下,我可能会选择在我的代码中稍微冗长一些,因为算法的意图很难传达。

An Update Of Your Fiddle

var groups = [
    {
        name:"group1",
        bit: 1
    },
    {
        name:"group2",
        bit: 2
    },
    {
        name:"group3",
        bit: 4
    }];

function parseIterations(groups){
    var aIterations = [];
    var aBits = [];
    var iGroups = groups.length;
    var iTotalIterations = Math.pow(2, iGroups);
    for (var i = 0; i < iTotalIterations; i++) {
        var oIteration = { groups: [] };
        for (var j = 0; j < iGroups; j++) {
            if (typeof aBits[j] == 'undefined')
                aBits[j] = true;
            // while you could infer the .bit value from j, 
            // i've chosen to use your .bit value here.
            aBits[j] = (i % groups[j].bit == 0) ? !aBits[j] : aBits[j];
            if (aBits[j])
                oIteration.groups.push(groups[j].name);
        }
        aIterations[i] = oIteration;
    }
    return aIterations;
}

var result = parseIterations(groups);

【讨论】:

  • 我喜欢这种情绪,但这仍然会重复多次,所以基本上是相同的答案。不过还是+1。谢谢你的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-08
相关资源
最近更新 更多