首先我們要知道什麼是笛卡爾積?
> 笛卡爾乘積是指在數學中,兩個集合X和Y的笛卡爾積(Cartesian product),又稱直積,表示為X × Y,第一個對象是X的成員而第二個對象是Y的所有可能有序對的其中一個成員。
百度百科
笛卡爾積的符号化為:
A×B={(x,y)|x∈A∧y∈B}
例如,A={a,b}, B={0,1,2},則
A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
B×A={(0, a), (0, b), (1, a), (1, b), (2, a), (2, b)}
那些場景會用到笛卡爾積呢?
- SQL中:
查詢的結果就是表tbl_a與表tbl_b的笛卡爾積。select * from tbl_a, tbl_b;
- 電商的商品中的銷售屬性決定了商品中的SKU數。比如:蘋果11,顔色:黃色/綠色/紅色/銀色,存儲:64GB/128GB/256GB,則我們可以購買的SKU就有4*3=12種。
顔色 | 存儲 |
---|---|
黃色 | 64GB |
黃色 | 128GB |
黃色 | 256GB |
綠色 | 64GB |
綠色 | 128GB |
綠色 | 256GB |
紅色 | 64GB |
紅色 | 128GB |
紅色 | 256GB |
銀色 | 64GB |
銀色 | 128GB |
銀色 | 256GB |
現在我們就電商商品的銷售屬性距離來實作。當然網上也存在着各種版本的實作。在此我也就不再重複寫了。有興趣的同學可以百度/Google一下。
下面是我個人的想法實作的,擴充性更強。
// 屬性數組
var props = [['黃色','綠色','紅色','銀色'],['64GB','128GB','256GB']];
/**
* 笛卡爾積計算sku總數
*/
var descartes = (pre = [], suf = []) => {
if(!pre || pre.length < 1){
return suf;
}
let result = [];
pre.forEach(o1 => {
suf.forEach(o2 => {
result.push(o1 + ',' + o2);
})
})
return result;
};
(function main(props){
// 定義最終的結果集
var res = [];
// 循環屬性清單 - 支援N種屬性
props.forEach(t => {
res = descartes(res, t);
//console.log(res);
})
console.log('笛卡爾積後:', res);
// 逆向
props.reverse();
res = [];
props.forEach(t => {
res = descartes(res, t);
//console.log(res);
})
console.log('逆向笛卡爾積後:', res);
})(props);
在浏覽器控制台運作結果:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL90EVOVTQq5EeVR0TzcmMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5ETNwMDMxIjMwIjMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
實際使用情況:
// 屬性數組
var props = [{"id": "p1", "name":"顔色","value":[{"id":"v1","name":'黃色'},{"id":"v2","name":'綠色'},{"id":"v3","name":'紅色'},{"id":"v4","name":'銀色'}]},{"id": "p2", "name":"存儲ROM","value":[{"id":"v5","name":'64GB'},{"id":"v6","name":'128GB'},{"id":"v7","name":'256GB'}]}];
/**
* 笛卡爾積計算sku總數
*/
var descartes = (last = [], cursor = {}) => {
let result = [];
let id = cursor.id;
let name = cursor.name;
last.forEach(o1 => {
(cursor.value || []).forEach(o2 => {
// 深拷貝
let temp = JSON.parse(JSON.stringify(o1));
temp[id] = {name,"pvId": o2.id,"pvName":o2.name};
result.push(temp);
})
})
return result;
};
(function main(props){
// 定義最終的結果集
var res = [{}];
// 循環屬性清單 - 支援N種屬性
props.forEach(t => {
res = descartes(res, t);
//console.log(res);
})
console.log('笛卡爾積後:', res);
// 逆向
props.reverse();
res = [{}];
props.forEach(t => {
res = descartes(res, t);
//console.log(res);
})
console.log('逆向笛卡爾積後:', res);
})(props);