如何使用 JavaScript 从二维数组的行中获取值的所有组合?
How to get all combination of the values from a 2D array's rows with JavaScript?
我正在使用的二维数组的每一行都有不同的长度,例如:
var a = [2, 5, -12, 9];
var b = [54.0, 0.3];
var c = ["tree", "sun", "pool"]
var all = [a, b, c]
二维数组中的任何行有时可能为零。上面的数组只是一个例子。
我想做的是从每个人的每一行中获取一个值,用这些值做一些事情,然后获取这些值的另一种组合,等等。
示例:
//IF ALL ROWS HAVE CONTENT
var values = [all[0][0], all[1][0], all[2][0]];
//do something with it
values = [all[0][0], all[1][0], all[2][1]];
//do something with it
......
values = [all[0][3], all[1][1], all[2][2]];
//do something with it
//IF FIRST AND THRID ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[0][0], all[2][0]];
values = [all[0][0], all[2][1]];
......
values = [all[0][3], all[2][2]];
//IF ONLY SECOND ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[1][0]];
values = [all[1][1]];
这是我对代码逻辑流程的看法
//count how many rows are not empty
var arrayCount = 0;
for(var i=0; i < all.length; i++){
if(all[i].length !== 0){
arrayCount++;
}
}
//store the combination of values each time
var values = [];
//reference for rows
var x; var y;
//differentiate the looping based on the number of unempty rows
switch(arrayCount){
//one unempty row
case 1:
//figure out which one is not empty and set a's pointer to it
for(var q = 0; q < x.length; q++){
values.push(x[q]);
//do something with it
values.splice(1, 0);
}
break;
case 2:
//figure out which one are not empty and set a and b's pointer to them (don't know how, maybe using two loops for each row?)
for(var q = 0; q < x.length; q++){
values.push(x[q]);
for(var p = 0; p < y.length; p++){
values.push(y[p]);
//do something with it
values.splice(1, 1);
}
values.splice(1, 0);
}
break;
case 3:
//set pointers to all the rows
for(var q = 0; q < x.length; q++){
values.push(x[q]);
for(var p = 0; p < y.length; p++){
values.push(y[p]);
for(var r = 0; r < z.length; r++){
values.push(z[r]);
//do something with it
values.splice(1, 2);
}
values.splice(1, 1);
}
values.splice(1, 0);
}
break;
}
恐怕整个代码太长了,开关中有一些重复的代码。可以简化一下吗?
我确实看到一个 有同样的问题,我尝试了它的答案。不幸的是,我正在编写代码的平台 (Fandom) 不支持这个生成器函数。我问,它只支持 Javascript 到 ES3 或 ES4。
感谢您查看此问题!
这是一个处理空数组且不使用生成器函数的解决方案。
var combinations = all.reduce(function (previous, current) {
if (current.length === 0)
return previous;
if (previous.length === 0)
return current;
const accumulate = current.map(function (x){
return previous.map(function(y) {
// Make one array if the accumulated result is an array
if (y.length > 0)
return y.concat(x);
return [x, y];
});
});
// Flatten combinations
return accumulate.reduce( function (acc, x) {
return acc.concat(x);
});
});
您可以采用递归方法,采用数组的数组并迭代每个内部数组,然后移交所收集项目的数组,直到没有更多数组可用为止。
function getCartesian(array) {
function iter(temp) {
var i = temp.length, j;
if (i >= array.length) {
return result.push(temp);
}
for (j = 0; j < array[i].length; j++) {
iter(temp.concat(array[i][j]));
}
}
var result = [];
iter([]);
return result;
}
console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
只有一个功能
function getCartesian(array) {
var i, j,
first = array.shift(),
temp = [],
result = [];
if (!first) return;
if (!array.length) return first;
temp = getCartesian(array);
for (i = 0; i < first.length; i++)
for (j = 0; j < temp.length; j++)
result.push([first[i]].concat(temp[j]));
return result;
}
console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
我 运行 this answer to a similar question through babel's online repl 得到了丑陋但可操作的代码,似乎可以满足您的要求。
注意:这里引用了 Symbol.iterator
,它在 ES4 中可能不可用。我没有研究过。上面的 babel link 包括原始解决方案和这个 t运行spilation 如果你想修改 babel 设置以实现兼容性。
我一开始没有post这个,因为看起来人们已经使用相同的算法回答了你的问题,没有 t运行spiling 的丑陋,但既然你问了......
这是根据您的示例输入得出的结果 运行:
const a = [2, 5, -12, 9];
const b = [54.0, 0.3];
const c = ["tree", "sun", "pool"];
const all = [a, b, c];
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
var makeCartesian = function makeCartesian() {
var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return function (a) {
for (var _len = arguments.length, more = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
more[_key - 1] = arguments[_key];
}
return a === undefined ? [t] : a.flatMap(function (x) {
return makeCartesian([].concat(_toConsumableArray(t), [x])).apply(void 0, more);
});
};
};
var cartesian = makeCartesian();
console.log(cartesian.apply(void 0, _toConsumableArray(all)));
我正在使用的二维数组的每一行都有不同的长度,例如:
var a = [2, 5, -12, 9];
var b = [54.0, 0.3];
var c = ["tree", "sun", "pool"]
var all = [a, b, c]
二维数组中的任何行有时可能为零。上面的数组只是一个例子。
我想做的是从每个人的每一行中获取一个值,用这些值做一些事情,然后获取这些值的另一种组合,等等。
示例:
//IF ALL ROWS HAVE CONTENT
var values = [all[0][0], all[1][0], all[2][0]];
//do something with it
values = [all[0][0], all[1][0], all[2][1]];
//do something with it
......
values = [all[0][3], all[1][1], all[2][2]];
//do something with it
//IF FIRST AND THRID ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[0][0], all[2][0]];
values = [all[0][0], all[2][1]];
......
values = [all[0][3], all[2][2]];
//IF ONLY SECOND ROWS HAVE CONTENT, THE SAMPLE OUTPUT
var values = [all[1][0]];
values = [all[1][1]];
这是我对代码逻辑流程的看法
//count how many rows are not empty
var arrayCount = 0;
for(var i=0; i < all.length; i++){
if(all[i].length !== 0){
arrayCount++;
}
}
//store the combination of values each time
var values = [];
//reference for rows
var x; var y;
//differentiate the looping based on the number of unempty rows
switch(arrayCount){
//one unempty row
case 1:
//figure out which one is not empty and set a's pointer to it
for(var q = 0; q < x.length; q++){
values.push(x[q]);
//do something with it
values.splice(1, 0);
}
break;
case 2:
//figure out which one are not empty and set a and b's pointer to them (don't know how, maybe using two loops for each row?)
for(var q = 0; q < x.length; q++){
values.push(x[q]);
for(var p = 0; p < y.length; p++){
values.push(y[p]);
//do something with it
values.splice(1, 1);
}
values.splice(1, 0);
}
break;
case 3:
//set pointers to all the rows
for(var q = 0; q < x.length; q++){
values.push(x[q]);
for(var p = 0; p < y.length; p++){
values.push(y[p]);
for(var r = 0; r < z.length; r++){
values.push(z[r]);
//do something with it
values.splice(1, 2);
}
values.splice(1, 1);
}
values.splice(1, 0);
}
break;
}
恐怕整个代码太长了,开关中有一些重复的代码。可以简化一下吗?
我确实看到一个
感谢您查看此问题!
这是一个处理空数组且不使用生成器函数的解决方案。
var combinations = all.reduce(function (previous, current) {
if (current.length === 0)
return previous;
if (previous.length === 0)
return current;
const accumulate = current.map(function (x){
return previous.map(function(y) {
// Make one array if the accumulated result is an array
if (y.length > 0)
return y.concat(x);
return [x, y];
});
});
// Flatten combinations
return accumulate.reduce( function (acc, x) {
return acc.concat(x);
});
});
您可以采用递归方法,采用数组的数组并迭代每个内部数组,然后移交所收集项目的数组,直到没有更多数组可用为止。
function getCartesian(array) {
function iter(temp) {
var i = temp.length, j;
if (i >= array.length) {
return result.push(temp);
}
for (j = 0; j < array[i].length; j++) {
iter(temp.concat(array[i][j]));
}
}
var result = [];
iter([]);
return result;
}
console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
只有一个功能
function getCartesian(array) {
var i, j,
first = array.shift(),
temp = [],
result = [];
if (!first) return;
if (!array.length) return first;
temp = getCartesian(array);
for (i = 0; i < first.length; i++)
for (j = 0; j < temp.length; j++)
result.push([first[i]].concat(temp[j]));
return result;
}
console.log(getCartesian([[2, 5, -12, 9], [54.0, 0.3], ["tree", "sun", "pool"]]).map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
我 运行 this answer to a similar question through babel's online repl 得到了丑陋但可操作的代码,似乎可以满足您的要求。
注意:这里引用了 Symbol.iterator
,它在 ES4 中可能不可用。我没有研究过。上面的 babel link 包括原始解决方案和这个 t运行spilation 如果你想修改 babel 设置以实现兼容性。
我一开始没有post这个,因为看起来人们已经使用相同的算法回答了你的问题,没有 t运行spiling 的丑陋,但既然你问了......
这是根据您的示例输入得出的结果 运行:
const a = [2, 5, -12, 9];
const b = [54.0, 0.3];
const c = ["tree", "sun", "pool"];
const all = [a, b, c];
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
var makeCartesian = function makeCartesian() {
var t = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return function (a) {
for (var _len = arguments.length, more = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
more[_key - 1] = arguments[_key];
}
return a === undefined ? [t] : a.flatMap(function (x) {
return makeCartesian([].concat(_toConsumableArray(t), [x])).apply(void 0, more);
});
};
};
var cartesian = makeCartesian();
console.log(cartesian.apply(void 0, _toConsumableArray(all)));