Calculate n-ary Cartesian Product

三世轮回 提交于 2019-11-29 03:55:10
Prelude> sequence [[1,2],[3,4],[5,6]]
[[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,3,5],[2,3,6],[2,4,5],[2,4,6]]

I found Eric Lippert's article on computing Cartesian product with LINQ quite helpful in improving my understanding of what was going on. Here's a more-or-less direct translation:

cartesianProduct :: [[a]] -> [[a]]
cartesianProduct sequences = foldr aggregator [[]] sequences
                   where aggregator sequence accumulator = 
                         [ item:accseq |item <- sequence, accseq <- accumulator ]

Or with more "Haskell-y" terse, meaningless parameter names ;)

cartesianProduct = foldr f [[]]
                    where f l a = [ x:xs | x <- l, xs <- a ]

This winds up being quite similar to sclv posted after all.

As a supplement to jleedev's answer (couldn't format this in the comments):

A quick unchecked substitution of list functions for monadic ones:

sequence ms = foldr k (return []) ms
   where
    k m m' = do { x <- m; xs <- m'; return (x:xs) }

....

    k m m' = m >>= \x -> m' >>= \xs -> [x:xs]
    k m m' = flip concatMap m $ \x -> flip concatMap m' $ \xs -> [x:xs]
    k m m' = concatMap (\x -> concatMap (\xs -> [x:xs]) m') m

....

sequence ms = foldr k ([[]]) ms
   where
     k m m' = concatMap (\x -> concatMap (\xs -> [x:xs]) m') m

If you want to have more control over the output, you can use a list as applicative functor, e.g.:

(\x y z -> [x,y,­z]) <$>  [1,2]­ <*> [4,5]­ <*> [6,7]

Let's say you want a list of tuples instead:

(\x y z -> (x,y,­z)) <$>  [1,2]­ <*> [4,5]­ <*> [6,7]

And it looks kind of cool, too...

Here is my way of implementing it simply, using only list comprehensions.

crossProduct :: [[a]] -> [[a]]
crossProduct (axis:[]) = [ [v] | v <- axis ]
crossProduct (axis:rest) = [ v:r | v <- axis, r <- crossProduct rest ]

You can do that in 2 ways:

  1. Using list comprehension

cp :: [[a]] -> [[a]]

cp [] = [[]]

cp (xs:xss) = [ x:ys | x <- xs, ys <- cp xss ]

  1. Using a fold

cp1 :: [[a]] -> [[a]]

cp1 xs = foldr f [[]] xs

  where f xs xss = [x:ys | x <- xs, ys <- xss]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!