输入:
[ [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;
};
答案 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);
答案 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次的原因。