工作解决方案;)
问题是,我实际上冲错了方向。我提出了以下想法,该想法使用了递归函数,因此使其更易于阅读。
确实,您希望拥有所有组合而没有排列。在这里,我只输入颜色的第一个字母。因此,来自:
b1 b2 g1 y1 y2 r1 r2 r3
A A B C C D D D
您想要拥有(这里的顺序就是代码的作用):
A B C D
b1 g1 y1 r1
b1 g1 y1 r2
b1 g1 y1 r3
b1 g1 y2 r1
b1 g1 y2 r2
b1 g1 y2 r3
b2 g1 y1 r1
b2 g1 y1 r2
b2 g1 y1 r3
b2 g1 y2 r1
b2 g1 y2 r2
b2 g1 y2 r3
首先,我想要列/颜色数组的另一种格式,因为使用起来会更容易。我想从
[b1,b2,g1,y1,y2,r1,r2,r3]
[A ,A ,B ,C ,C ,D ,D ,D]
到
[[b1,b2],[g1],[y1,y2],[r1,r2,r3]]
[ A , B , C , D ]
这样,对于每个列值,我们将拥有一个匹配的子数组,该子数组包含与该列相关的所有颜色。
以下功能可以达到此目的(即使这可能不是实现此目的的最佳方法):
//column and color are the paired arrays you have as data input
function arrangeArrays(column, color) {
var ret=new Array(); //the returned container for the data
ret["color"]=new Array(); //the color part of the returned data
ret["column"]=new Array(); //the column part of the returned data
var tmp=new Array(); //an internal array we'll use to switch from associative keys to normal keys
//we parse the paired arrays
for(var i in column) {
//if the column is not an associative key in tmp, we declare it as an array
if(!tmp[column[i]])
tmp[column[i]]=new Array();
//we add the color to the subarray matching its column
tmp[column[i]].push(color[i]);
}
//Now we just translate these horrible associative keys into cute array-standard integer keys
for(var i in tmp) {
ret["color"].push(tmp[i]);
ret["column"].push(i);
}
//the commented code is a quick does-it-work block
/*
for(var i in ret["column"]) {
document.write("column="+ret["column"][i]+" --- color(s)="+ret["color"][i].join()+"<br>");
}
*/
return ret;
}
现在到了核心。每次对该函数的调用都将处理一列,实际上仅处理其中一部分,使用递归处理其他列。使用一个简化的示例,代码执行以下操作:
[[b1,b2],[y1,y2]]
[ A , B ]
total combinations: 2*2=4
first call for 1st column, length is 4, 2 possible values, first insert loops 4/2=2 times:
b1
b1
call for 2nd column, length is 2, 2 possible values, first insert loops 2/2=1 time:
b1 y1
b1
call for 3rd column, no 3rd column, coming back
call for 2nd column, length is 2, 2 possible values, second insert loops 2/2=1 time:
b1 y1
b1 y2
call for 3rd column, no 3rd column, coming back
call for 2nd column done, coming back
first call for 1st column, length is 4, 2 possible values, second insert loops 4/2=2 times:
b1 y1
b1 y2
b2
b2
call for 2nd column, length is 2, 2 possible values, first insert loops 2/2=1 time:
b1 y1
b1 y2
b2 y1
b2
call for 3rd column, no 3rd column, coming back
call for 2nd column, length is 2, 2 possible values, second insert loops 2/2=1 time:
b1 y1
b1 y2
b2 y1
b2 y2
call for 3rd column, no 3rd column, coming back
call for 2nd column done, coming back
call for 1st column done, coming back (returning)
这是代码,帮助您自己阅读注释;)
//results is an empty array, it is used internally to pass the processed data through recursive calls
//column and color would be the subarrays indexed by "column" and "color" from the data received by arrangeArrays()
//resultIndex is zero, it is used for recursive calls, to kNow where we start inserting data in results
//length is the total of results expected; in our example, we have 2 blues, 1 green, 2 yellows, and 3 reds: the total number of combinations will be 2*1*2*3, it's 12
//resourceIndex is zero, used for recursive calls, to kNow what column we are to insert in results
function go(results, column, color, resultIndex, length, resourceIndex) {
//this case stops the recursion, it means the current call tries to exceed the length of the resource arrays; so we just return the data without touching it
if(resourceIndex>=column.length)
return results;
//we loop on every color mentioned in a column
for(var i=0;i<color[resourceIndex].length;i++) {
//so for every color, we Now insert it as many times as needed, which is the length parameter divided by the possible values for this column
for(var j=0;j<length/color[resourceIndex].length;j++) {
//ci will be the index of the final array
//it has an offset due to recursion (resultIndex)
//each step is represented by j
//we have to jump "packs" of steps because of the loop containing this one, which is represented by i*(the maximum j can reach)
var ci=resultIndex+i*(length/color[resourceIndex].length)+j;
//the first time we use ci, we have to declare results[ci] as an array
if(!results[ci])
results[ci]=new Array();
//this is it, we insert the color into its matching column, and this in all the indexes specified through the length parameter
results[ci][column[resourceIndex]]=color[resourceIndex][i];
} //end of j-loop
//we call recursion Now for the columns after this one and on the indexes of results we started to build
results=go(results, column, color, resultIndex+i*(length/color[resourceIndex].length), length/color[resourceIndex].length, resourceIndex+1);
} //end of i-loop
//we Now pass the data back to the prevIoUs call (or the script if it was the first call)
return results;
}
我使用以下代码测试了该功能(如果您想体验每一步会发生什么,可能会很有用):
function parseResults(res) {
for(x in res) { //x is an index of the array (integer)
for(var y in res[x]) { //y is a column name
document.write(x+" : "+y+" = "+res[x][y]); //res[x][y] is a color
document.write("<br>");
}
document.write("<br>");
}
}
您可能还需要一个函数来告知go()
第一次调用要使用的长度。像这个:
function getLength(color) {
var r=1;
for(var i in color)
r*=color[i].length;
return r;
}
var arrangedArrays=arrangeArrays(column, color);
var res=go(new Array(), arrangedArrays["column"], arrangedArrays["color"], 0, getLength(arrangedArrays["color"]), 0);
在这里看起来似乎很大,但是我想很好地解释一下,无论如何,如果您删除了代码和示例中的注释,就没有那么大了……整个事情就是不要对这些索引发疯了;)
您可以使用“关联数组”(或eval
类似对象/属性的语法,大致相同)。像这样的东西:
var arrayResult=new Array();
var resultLength=0;
for(var globalCounter=0;globalCounter<arrayColumn.length;globalCounter++) {
//if this subarray hasn't been init'd yet, we do it first
if(!arrayResult[resultLength])
arrayResult[resultLength]=new Array();
//case: we already inserted a color for the current column name
if(arrayResult[resultLength][arrayColumn[globalCounter]]) {
//1: we copy the current subarray of arrayResult to a new one
resultLength++;
arrayResult[resultLength]=new Array();
for(var i=0;i<=globalCounter;i++)
arrayResult[resultLength][arrayColumn[i]]=arrayResult[resultLength-1][arrayColumn[i]];
//2: we replace the value for the conflicting colmun
arrayResult[resultLength][arrayColumn[globalCounter]]=arrayColor[globalCounter];
//case: default, the column wasn't already inserted
} else {
//we simply add the column to each subarray of arrayResult
for(var i=0;i<=resultLength;i++)
arrayResult[i][arrayColumn[globalCounter]]=arrayColor[globalCounter];
}
}
从这里开始,我想很容易将其转换为JSON格式。
解析子数组时,请记住, ,即,您不能使用循环for
(x=0;x<array.length;x++),而应
使用for(x in array)
; 并且您必须测试密钥,并确保在处理之前以“ column”开头(否则您将结束对“ length” / 0 ^^对的处理)。如果您希望此容器数组具有这种键,则对arrayResult的键相同。
最后一件事:我没有测试代码,它可能会漏掉一点,或者可能有些混乱。目的是帮助,而不是做:)
祝你好运!