[JavaScript] 求解任意n個集合的笛卡爾積
假設我們有兩個集合,A={1, 2, 3}
,B={'a', 'b'}
,
我們怎樣求解這兩個集合的笛卡爾積呢?
A × B = {(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')}
我們想到Haskell中的list comprehension正好有這種功能。
(1)list comprehension
ghci> [(x, y) | x <- [1, 2, 3], y <- ['a','b']]
ghci> [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
(2)do-notaion
list comprehension實際上是do-notation的語法糖,
do
x <- [1, 2, 3]
y <- ['a','b']
return (x, y)
(3)函式>>=
然而,do-notation也是一個語法糖,
[1, 2, 3] >>= (\x -> ['a', 'b'] >>= (\y -> return (x, y)))
可是>>=
是什麼呢?它是一個高階函式,我們來看list monad的定義,
instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
fail _ = []
其中,
concat :: [[a]] -> [a]
map :: (a -> b) -> [a] -> [b]
(4)我們來證明一下
[1, 2, 3] >>= (\x -> ['a', 'b'] >>= (\y -> return (x, y)))
concat $ map (\x -> ['a', 'b'] >>= (\y -> return (x, y))) [1, 2, 3]
我們先看
(\x -> ['a', 'b'] >>= (\y -> return (x, y))) 1
['a', 'b'] >>= (\y -> return (1, y))
concat $ map (\y -> return (1, y)) ['a', 'b']
我們再看
(\y -> return (1, y)) 'a'
return (1, 'a')
[(1, 'a')]
然後,後退一步
concat $ map (\y -> return (1, y)) ['a', 'b']
concat [[(1, 'a')], [(1, 'b')]]
[(1, 'a'), (1, 'b')]
再後退一步
concat $ map (\x -> ['a', 'b'] >>= (\y -> return (x, y))) [1, 2, 3]
concat [[(1, 'a'), (1, 'b')], [(2, 'a'), (2, 'b')], [(3, 'a'), (3, 'b')]]
[(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
證畢。
(5)用JavaScript來實現
先把>>=
都去掉,
[1, 2, 3] >>= (\x -> ['a', 'b'] >>= (\y -> return (x, y)))
concat $ map (\x -> ['a', 'b'] >>= (\y -> return (x, y))) [1, 2, 3]
concat $ map (\x -> concat $ map (\y -> return (x, y)) ['a', 'b']) [1, 2, 3]
然後,分別實現concat
和map
function concat(array) {
return [].concat.apply([], array);
}
function map(fn, array) {
return [].map.call(array, fn);
}
concat(map(
x=>concat(map(
y=>[[x,y]],
['a', 'b']
)),
[1, 2, 3]
));
簡化一下:
function flatMap(fn, array) {
return concat(map(fn, array));
}
flatMap(
x=>flatMap(
y=>[[x,y]],
['a', 'b']
),
[1, 2, 3]
);
(6)任意n個集合的笛卡爾積
export default function cartesianProduct(sets) {
let head = sets.shift();
if (sets.length === 0) {
return map(
item => [item],
head
);
}
let tailProduct = cartesianProduct(sets);
return flatMap(
item => flatMap(
items => [[item, ...items]],
tailProduct
),
head
);
}
function concat(array) {
return [].concat.apply([], array);
}
function map(fn, array) {
return [].map.call(array, fn);
}
function flatMap(fn, array) {
return concat(map(fn, array));
}
測試,
cartesianProduct([[1, 2, 3],['a', 'b']])
=== [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]]
相關文章
- php計算多個集合的笛卡爾積例項詳解PHP
- java 笛卡爾積(迴圈)Java
- 笛卡爾乘積的javascript版實現和應用JavaScript
- 笛卡爾積與全連線
- 笛卡爾積的應用——商品 SKU 計算
- Oracle的表連線方法(四)笛卡爾積Oracle
- 笛卡爾積和NEST LOOP產生的影響OOP
- 二維陣列笛卡爾積js實現陣列JS
- 笛卡爾樹
- Python如何從列表中獲取笛卡爾積Python
- 【TUNE_ORACLE】列出走了笛卡爾積的SQL參考OracleSQL
- 成績錄入SQL語句 笛卡爾積 LEFT JOINSQL
- SQL 語句調優_減少或者避免笛卡爾乘積的發生SQL
- SparkSQL中產生笛卡爾積的幾種典型場景以及處理策略SparkSQL
- 基環樹和笛卡爾樹
- 統計資訊不準確導致執行計劃走了笛卡爾積
- 理解笛卡爾積在資料庫查詢中的實際應用與最佳化資料庫
- 笛卡爾座標張量簡介7
- 集合的前N個元素
- 二叉查詢樹和笛卡爾樹
- 笛卡爾實驗室全面遷移至亞馬遜雲科技亞馬遜
- 科學的演變:從笛卡爾到生成式人工智慧人工智慧
- 笛卡爾:語言是思想唯一確定標誌?
- C++ opencv的圓轉矩形,極座標轉笛卡爾座標系C++OpenCV
- 形象化理解笛卡爾座標系和極座標系
- P1377 [TJOI2011] 樹的序 (笛卡爾樹)
- 遞迴求解二叉樹任意一結點的深度遞迴二叉樹
- JavaScript中任意兩個數加減的解決方案JavaScript
- jQuery在元素集合中獲取第N個元素jQuery
- [演算法] 兩個質數的乘積是707829217,求解該質數演算法
- JavaScript 獲取第n個li元素JavaScript
- 演算法:利用分治演算法求解N個元素中的第M大元素演算法
- 計算任意多邊形的面積(Android)Android
- 流體力學守恆形式Euler方程(笛卡爾座標、柱座標、球座標)
- 關於求解不定方程的n(n-1)=2m(m-1)的解法的總結
- 階乘之和 輸入n,計算S=1!+2!+3!+…+n!的末6位(不含前導0)。n≤10 6 ,n!表示 前n個正整數之積。
- JavaScript 中的表示任意精度的 BigIntJavaScript
- JavaScript FileList 集合JavaScript