天天看點

笛卡爾積實作-JavaScript版

首先我們要知道什麼是笛卡爾積?

百度百科

> 笛卡爾乘積是指在數學中,兩個集合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中:

    select * from tbl_a, tbl_b;

    查詢的結果就是表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);
           

在浏覽器控制台運作結果:

笛卡爾積實作-JavaScript版

實際使用情況:

// 屬性數組
	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);
           

實際運作結果:

笛卡爾積實作-JavaScript版

效果圖:

笛卡爾積實作-JavaScript版
笛卡爾積實作-JavaScript版

繼續閱讀