vtils
Version:
一个面向业务的 JavaScript/TypeScript 实用程序库。
103 lines (101 loc) • 3.44 kB
JavaScript
var supportNewFunction = function () {
try {
return new Function('return 1')() === 1;
} catch (err) {
return false;
}
}();
/**
* 计算多个数组的笛卡尔积。
*
* @param arr 数组内容
* @example
* ```typescript
* cartesianProduct([
* ['a', 'b'],
* [1, 2],
* ])
* // => [['a', 1], ['a', 2], ['b', 1], ['b', 2]]
* ```
*/
export function cartesianProduct(arr) {
if (!Array.isArray(arr)) {
throw new Error('cartesianProduct expects an array');
}
if (!arr.length) {
return [];
}
if (!Array.isArray(arr[0])) {
throw new Error('set at index 0 must be an array');
}
return (supportNewFunction && arr.length < 100 ?
// 在支持动态构造函数环境下,并且数组长度小于 100 时使用快速模式
cartesianProductProviders.fast :
// 否则使用通用模式,如:小程序、数组长度大于等于 100
cartesianProductProviders.universal).run(arr);
}
var cartesianProductProviders = {
// https://github.com/angus-c/just/blob/master/packages/array-cartesian-product/index.js
universal: {
run: function run(arr) {
// initialize our product array
var product = arr[0].map(function (v) {
return [v];
});
for (var i = 1; i < arr.length; i++) {
if (!Array.isArray(arr[i])) {
throw new Error("set at index " + i + " must be an array");
}
product = cartesianProductProviders.universal.baseProduct(product, arr[i]);
}
return product;
},
baseProduct: function baseProduct(prevProduct, arr2) {
// pre allocate all our memory
var newProduct = new Array(prevProduct.length * arr2.length);
for (var i = 0; i < prevProduct.length; i++) {
for (var j = 0; j < arr2.length; j++) {
// always provide array to array.concat for consistent behavior
newProduct[i * arr2.length + j] = prevProduct[i].concat([arr2[j]]);
}
}
return newProduct;
}
},
// https://github.com/ehmicky/fast-cartesian/blob/main/src/main.js
fast: {
cache: Object.create(null),
run: function run(arr) {
var loopFunc = cartesianProductProviders.fast.getLoopFunc(arr.length);
var result = [];
loopFunc(arr, result);
return result;
},
getLoopFunc: function getLoopFunc(length) {
var cachedLoopFunc = cartesianProductProviders.fast.cache[length];
if (cachedLoopFunc !== undefined) {
return cachedLoopFunc;
}
var loopFunc = cartesianProductProviders.fast.mGetLoopFunc(length);
cartesianProductProviders.fast.cache[length] = loopFunc;
return loopFunc;
},
mGetLoopFunc: function mGetLoopFunc(length) {
var prefixArr = [];
var startArr = [];
var middleArr = [];
var endArr = [];
for (var i = 0; i < length; i++) {
prefixArr.push("if (!Array.isArray(arrays[" + i + "])) { throw new Error('set at index " + i + " must be an array') }");
startArr.push("for (var i" + i + " = 0; i" + i + " < arrays[" + i + "].length; i" + i + "++) {");
middleArr.push("arrays[" + i + "][i" + i + "]");
endArr.push("}");
}
var prefix = prefixArr.join('\n');
var start = startArr.join('\n');
var middle = middleArr.join(',');
var end = endArr.join('\n');
return new Function('arrays', 'result', prefix + "\n" + start + "\nresult.push([" + middle + "])\n" + end);
}
}
};