获取所有可能集的算法

时间:2013-11-18 08:17:26

标签: javascript algorithm node.js

输入:

[ [a1,b1,c1], [a2,b2,c2,d,2], [a3,b3], ...]

输出:

[ [a1,a2,a3], [a1,a2,b3], [a1,b2,a3], [a1,b2,b3], [a1,c2,a3], [a1,c2,b3], ... ]

所以我需要所有可能的组合(顺序无关紧要)。每个输出集nth成员都是nth输入集的成员。我需要高效的算法,最好是在javascript中。


修改

我正在努力解决这个问题。

var input = [ [a,b,c], [a1,b1,c1], [a2,b2] ];

var combinationsNum = _.reduce(input,function(num,set){ return num*set.length; }, 1);
var output = new Array(combinationsNum);
for(var i = 0; i < output.length; ++i) output[i] = [];

for(var s = 0; s < input.length; ++s) {
    var set = input[s];
    for(var m = 0; m < set.length; ++m) {
        var memeber = set[m];
        // now I need to calculate to which output arrays I have to push this member
    }
}

// result should be
// a a1 a2
// a b1 b2
// a c1 a2
// a a1 b2
// a b1 a2
// a c1 b2
// b a1 a2
// b b1 b2
// b c1 a2
// b a1 b2
// b b1 a2
// b c1 b2
// c a1 a2
// c b1 b2
// c c1 a2
// c a1 b2
// c b1 a2
// c c1 b2

正如你在每个set上看到的那样,我必须将每个成员推送到每个输出数组,并且有一些间隔和时间......我有计算这个的问题......


我在这个重复的问题中找到的最快的方法是:

function(arg) {
    var r = [], max = arg.length-1;
    function helper(arr, i) {
        for (var j=0, l=arg[i].length; j<l; j++) {
            var a = arr.slice(0); // clone arr
            a.push(arg[i][j])
            if (i==max) {
                r.push(a);
            } else
                helper(a, i+1);
        }
    }
    helper([], 0);
    return r;
};

3 个答案:

答案 0 :(得分:1)

实现此目的的一种可能方法是使用递归。我不熟悉JavaScript,以下是C ++版本。你可以相应地调整它。

#include <iostream>
#include <vector>

using namespace std;

vector< vector<int> > input;

void recurCombination( vector<int>& outputSoFar ) {

  // base case: If number of entries in our output = size of input array, then print it.
  if ( outputSoFar.size() == input.size() ) {
    // print outputSoFar
    return;
  }

  // else take next subarray in the input array.
  int sizeSofar = outputSoFar.size();    

  // for each element in that subarray, choose an element and recur further.
  for ( int i = 0; i < input[sizeSoFar].size(); i++ ) {
    vector<int> newSoFar( outputSoFar );
    newSoFar.push_back( input[sizeSoFar][i] );
    recurCombination( newSoFar )

  }

}

int main() {

  // read input vector
  vector<int> emptySoFar;
  recurCombination( emptySoFar );

  return 0;
}

答案 1 :(得分:1)

由于输出中的元素数量为length1*length2*...lengthN,因此只需迭代每个数组并构建输出的算法就是最有效的算法。

function buildAll(arr){  
  var i;
  // count the total number of arrays in the output
  var count = 1;
  for (i=0; i<arr.length; i++) {
    count *= arr[i].length; // fails if empty arrays are in input, make sure you extract those
  }

  // prepare the output arrays
  var output = [];
  for (i=0; i<count; i++) {
    output.push([]);
  }

  // fill the arrays
  var total = count;
  for (i=0; i<arr.length; i++) {
    count /= arr[i].length;
    for (var k=0; k<total; k++) {
      output[k].push(arr[i][Math.floor((k/count)%arr[i].length)]);      
    }    
  }

  return output;
}


// usage
var input = [ ['a1','b1','c1'], ['a2','b2','c2','d2'], ['a3','b3']];
var output = buildAll(input);
console.log(output);

DEMO:http://jsbin.com/UfAnIMus/1/edit

答案 2 :(得分:1)

function concat(a, b)
{
    return a.concat(b);
}

function combinations(a)
{
    return a.length == 0 ? [[]] : a[0].map(function(x) {
        return combinations(a.slice(1)).map(concat.bind(null, [x]));
    }).reduce(concat, []);
}

无法抗拒;)


编辑:

这是原始代码的固定版本。

var lengths = input.map(function(a) { return a.length; });
function product(arr) { return arr.reduce(function(a, b) { return a * b; }, 1); }

var numCombinations = product(lengths);
var output = new Array(numCombinations);

for(var i = 0; i < output.length; ++i) output[i] = [];

for(var s = 0; s < input.length; ++s) {
    var set = input[s];
    var runLength = product(lengths.slice(s + 1));
    var j = 0;
    while (j < numCombinations) {
        for (var m = 0; m < set.length; ++m) {
            for (var i = 0; i < runLength; i++) {
                output[j][s] = set[m];
                j++;
            }
        }
    }
}

说明:

任何给定数组位置的模式都相对简单。例如,考虑集合 [{a1,b1,c1},{a2,b2,c2},{a3,b3}] 的可能组合:

[a1,a2,a3]
   [a1,a2,b3]
   [a1,b2,a3]
   [a1,b2,b3]
   [a1,c2,a3]
   [a1,c2,b3]
   [b1,a2,a3]
   [b1,a2,b3]
   [b1,b2,a3]
  ...

第二列中的元素循环通过值 {a2,b2,c2} ,每个元素重复两次。通常,重复次数等于剩余组的组合数(它们的大小的乘积)。第二列之后唯一剩下的设置是 {a3,b3} ,其大小为2,因此每个元素出现两次。对于第一列,其余的集合是 {a2,b2,c2} {a3,b3} ,因此其大小的乘积为3×2 = 6,其中是 a1 出现6次的原因。