[英]Calculate n-ary Cartesian Product
Given two lists, I can produce
a list of all permutations
the Cartesian Product of these two lists:给定两个列表,我可以生成这两个列表的笛卡尔积的
所有排列
列表:
permute :: [a] -> [a] -> [[a]]
permute xs ys = [ [x, y] | x <- xs, y <- ys ]
Example> permute [1,2] [3,4] == [ [1,3], [1,4], [2,3], [2,4] ]
How do I extend permute so that instead of taking two lists, it takes a list (length n) of lists and returns a list of lists (length n)我如何扩展 permute 以便它不采用两个列表,而是采用列表的列表(长度 n)并返回列表的列表(长度 n)
permute :: [[a]] -> [[a]]
Example> permute [ [1,2], [3,4], [5,6] ]
== [ [1,3,5], [1,3,6], [1,4,5], [1,4,6] ] --etc
I couldn't find anything relevant on Hoogle.. the only function matching the signature was transpose
, which doesn't produce the desired output.我在 Hoogle 上找不到任何相关内容。唯一匹配签名的函数是transpose
,它不会产生所需的输出。
Edit: I think the 2-list version of this is essentially the Cartesian Product , but I can't wrap my head around implementing the n-ary Cartesian Product .编辑:我认为这个 2-list 版本本质上是Cartesian Product ,但我无法围绕实现n-ary Cartesian Product 。 Any pointers?任何指针?
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.我发现 Eric Lippert 关于使用 LINQ 计算笛卡尔积的文章对提高我对正在发生的事情的理解很有帮助。 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 ;)或者使用更多“Haskell-y”简洁、无意义的参数名称;)
cartesianProduct = foldr f [[]]
where f l a = [ x:xs | x <- l, xs <- a ]
This winds up being quite similar to sclv posted after all.毕竟这与发布的 sclv 非常相似。
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 ]
As a supplement to jleedev's answer (couldn't format this in the comments):作为 jleedev 答案的补充(无法在评论中对此进行格式化):
A quick unchecked substitution of list functions for monadic ones:对 monadic 函数的列表函数的快速未经检查的替换:
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, eg:如果你想对输出有更多的控制,你可以使用列表作为应用函子,例如:
(\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...而且看起来也很酷……
You can do this in 2 ways:您可以通过两种方式执行此操作:
cp :: [[a]] -> [[a]] cp [] = [[]] cp (xs:xss) = [ x:ys | x <- xs, ys <- cp xss ]
cp1 :: [[a]] -> [[a]] cp1 xs = foldr f [[]] xs where f xs xss = [x:ys | x <- xs, ys <- xss]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.