[JavaScript] 求解任意n個(gè)集合的笛卡爾積

假設(shè)我們有兩個(gè)集合,A={1, 2, 3}B={'a', 'b'},
我們?cè)鯓忧蠼膺@兩個(gè)集合的笛卡爾積呢?

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實(shí)際上是do-notation的語(yǔ)法糖,

do
    x <- [1, 2, 3]
    y <- ['a','b']
    return (x, y)

(3)函數(shù)>>=

然而,do-notation也是一個(gè)語(yǔ)法糖,

[1, 2, 3] >>= (\x -> ['a', 'b'] >>= (\y -> return (x, y)))

可是>>=是什么呢?它是一個(gè)高階函數(shù),我們來(lái)看list monad的定義,

instance Monad [] where
    return x = [x]
    xs >>= f = concat (map f xs)
    fail _ = []

其中,

concat :: [[a]] -> [a]
map :: (a -> b) -> [a] -> [b]

(4)我們來(lái)證明一下

[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']

我們?cè)倏?/p>

(\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來(lái)實(shí)現(xiàn)

先把>>=都去掉,

[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]

然后,分別實(shí)現(xiàn)concatmap

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]
));

簡(jiǎn)化一下:

function flatMap(fn, array) {
    return concat(map(fn, array));
}

flatMap(
    x=>flatMap(
        y=>[[x,y]], 
        ['a', 'b']
    ),
    [1, 2, 3]
);

(6)任意n個(gè)集合的笛卡爾積

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));
}

測(cè)試,

cartesianProduct([[1, 2, 3],['a', 'b']])
=== [[1, "a"], [1, "b"], [2, "a"], [2, "b"], [3, "a"], [3, "b"]]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容