什么是笛卡尔积
笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尓积(Cartesian product),又称直积,表示为X×Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。
例如:
假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为:
{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}.
在Javascript中的实现
为数组增加一个分块方法
/**
* 把一个数组分割成新的数组块
* @param data
* @param size
*
* chunk(['a', 'b', 'c', 'd'], 2);
* // => [['a', 'b'], ['c', 'd']]
*
* chunk(['a', 'b', 'c', 'd'], 3);
* // => [['a', 'b', 'c'], ['d']]
*/
const chunk = function (data: any[], size: number = 1): any[][] {
size = Math.max(+size || 1, 1);
let index = 0;
let resIndex = -1;
const length = data.length;
const result = Array(Math.ceil(length / size));
while (index < length) {
result[++resIndex] = data.slice(index, (index += size));
}
return result;
};
基础实现
function descartes(t: any[]){
let a = t.shift(),
r,
b;
!(a.constructor === Array) && (a = [a]);
a = chunk(a, 1);
do{
r = [];
b = t.shift();
!(b.constructor === Array) && (b = [b]);
a.forEach( function(p) {
chunk(b, 1).forEach( function(q) {
r.push(p.concat(q));
});
});
a = r;
}while(t.length > 0);
return r;
}
let arr = [
['黑色','红色'],
['透气','防滑'],
['37码','38码','39码']
];
console.log(descartes(arr));
输出
[
[ '黑色', '透气', '37码' ],
[ '黑色', '透气', '38码' ],
[ '黑色', '透气', '39码' ],
[ '黑色', '防滑', '37码' ],
[ '黑色', '防滑', '38码' ],
[ '黑色', '防滑', '39码' ],
[ '红色', '透气', '37码' ],
[ '红色', '透气', '38码' ],
[ '红色', '透气', '39码' ],
[ '红色', '防滑', '37码' ],
[ '红色', '防滑', '38码' ],
[ '红色', '防滑', '39码' ]
]
扩展到项目
interface SkuUnitStruct {
attrId?: string;
attrName: string;
optionId?: string;
optionName: string;
name: string;
}
/**
* 根据属性和属性的选项 计算笛卡尔积
* @param attrWithOptions
*/
function calcDescartes(attrWithOptions: any[]): any[][] {
if (attrWithOptions.length < 1) {
return [];
}
attrWithOptions.forEach((attr) => {
attr.options.forEach((option) => {
option.attr_id = attr.id as string;
option.attr_name = attr.name;
});
});
const attrs: any[] = JSON.parse(
JSON.stringify(attrWithOptions)
);
const firstAttr = attrs.shift();
let secondAttr: any;
let firstOptionChucks: any[][] = chunk(firstAttr.options, 1);
let result: any[][] = firstOptionChucks;
while (attrs.length > 0) {
result = [];
secondAttr = attrs.shift();
const secondOptionChucks: any[][] = chunk(
secondAttr.options,
1
);
firstOptionChucks.forEach(function (previousOptions) {
secondOptionChucks.forEach(function (currentOptions) {
result.push(previousOptions.concat(currentOptions));
});
});
firstOptionChucks = result;
}
return result;
}
let attrWithOptions = [
{
"id": "", "name": "运营商", "options": [
{ "id": "", "name": "电信", "attr_id": "", "attr_name": "运营商" },
{ "id": "", "name": "移动", "attr_id": "", "attr_name": "运营商" },
{ "id": "", "name": "联通", "attr_id": "", "attr_name": "运营商" }
]
},
{
"id": "", "name": "网络", "options": [
{ "id": "", "name": "4G", "attr_id": "", "attr_name": "网络" },
{ "id": "", "name": "5G", "attr_id": "", "attr_name": "网络" }
]
},
{
"id": "", "name": "颜色", "options": [
{ "id": "", "name": "黑色", "attr_id": "", "attr_name": "颜色"},
{ "id": "", "name": "白色", "attr_id": "", "attr_name": "颜色" }
]
}
];
console.log(calcDescartes(attrWithOptions));
输出
[
[
{ id: '', name: '电信', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '电信', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '电信', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '电信', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '移动', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '移动', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '移动', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '移动', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '联通', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '联通', attr_id: '', attr_name: '运营商' },
{ id: '', name: '4G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '联通', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '黑色', attr_id: '', attr_name: '颜色' }
],
[
{ id: '', name: '联通', attr_id: '', attr_name: '运营商' },
{ id: '', name: '5G', attr_id: '', attr_name: '网络' },
{ id: '', name: '白色', attr_id: '', attr_name: '颜色' }
]
]