[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"]]
相關文章
- 笛卡爾乘積的javascript版實現和應用JavaScript
- 笛卡爾積的應用——商品 SKU 計算
- 笛卡爾樹
- 二維陣列笛卡爾積js實現陣列JS
- Python如何從列表中獲取笛卡爾積Python
- 【TUNE_ORACLE】列出走了笛卡爾積的SQL參考OracleSQL
- 基環樹和笛卡爾樹
- SparkSQL中產生笛卡爾積的幾種典型場景以及處理策略SparkSQL
- 【笛卡爾樹+DP】【SP3734】 PERIODNI - Periodni
- 笛卡爾座標張量簡介7
- 理解笛卡爾積在資料庫查詢中的實際應用與最佳化資料庫
- 二叉查詢樹和笛卡爾樹
- P1377 [TJOI2011] 樹的序 (笛卡爾樹)
- 笨辦法學C 導言:C的笛卡爾之夢
- 科學的演變:從笛卡爾到生成式人工智慧人工智慧
- 笛卡爾:語言是思想唯一確定標誌?
- 笛卡爾實驗室全面遷移至亞馬遜雲科技亞馬遜
- C++ opencv的圓轉矩形,極座標轉笛卡爾座標系C++OpenCV
- 形象化理解笛卡爾座標系和極座標系
- 畢設(5)—笛卡爾空間軌跡規劃(直線、圓弧)
- JavaScript中任意兩個數加減的解決方案JavaScript
- 流體力學守恆形式Euler方程(笛卡爾座標、柱座標、球座標)
- JavaScript 獲取第n個li元素JavaScript
- [演算法] 兩個質數的乘積是707829217,求解該質數演算法
- JavaScript 中的表示任意精度的 BigIntJavaScript
- 計算任意多邊形的面積(Android)Android
- 演算法:利用分治演算法求解N個元素中的第M大元素演算法
- [譯]BigInt:JavaScript 中的任意精度整型JavaScript
- JavaScript 元素集合JavaScript
- JavaScript FileList 集合JavaScript
- 笛卡爾空間力反饋的關節速度控制之機器人運動學庫KDL安裝及使用機器人
- 卡米黛爾系統卡米黛爾商城系統
- 計算機求解10進位制轉換任意進位制計算機
- JavaScript select options 集合JavaScript
- 卡爾曼濾波
- SciTech-Mathmatics-Analysis: 定積分 求解的“十大公式”公式
- JavaScript數字開任意次方運算JavaScript
- 輸入n個元素組成的序列s,你需要找出一個乘積最大的連續子序列
- 求解一個陣列的所有子集陣列