给定两个列表,我可以生成所有排列的列表这两个列表的笛卡尔积:
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] ]
如何扩展置换,以便不使用两个列表,而是列出一个列表(长度为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
我找不到与Hoogle相关的任何内容..与签名匹配的唯一功能是transpose
,这不会产生所需的输出。
编辑:我认为这个2列表版本基本上是Cartesian Product,但我不能完全实现n-ary Cartesian Product。有什么指针吗?
答案 0 :(得分:23)
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]]
答案 1 :(得分:4)
我发现Eric Lippert关于computing Cartesian product with LINQ的文章对于提高我对正在发生的事情的理解非常有帮助。这是一个或多或少的直接翻译:
cartesianProduct :: [[a]] -> [[a]]
cartesianProduct sequences = foldr aggregator [[]] sequences
where aggregator sequence accumulator =
[ item:accseq |item <- sequence, accseq <- accumulator ]
或者更多“Haskell-y”简洁,无意义的参数名称;)
cartesianProduct = foldr f [[]]
where f l a = [ x:xs | x <- l, xs <- a ]
这最终与sclv完全相似。
答案 2 :(得分:3)
作为对jleedev答案的补充(无法在评论中对此进行格式化):
快速取消选中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
答案 3 :(得分:2)
如果您想要更多地控制输出,可以使用列表作为applicative functor,例如:
(\x y z -> [x,y,z]) <$> [1,2] <*> [4,5] <*> [6,7]
假设你想要一个元组列表:
(\x y z -> (x,y,z)) <$> [1,2] <*> [4,5] <*> [6,7]
它看起来也很酷......
答案 4 :(得分:2)
这是我简单实现它的方法,仅使用列表推导。
crossProduct :: [[a]] -> [[a]]
crossProduct (axis:[]) = [ [v] | v <- axis ]
crossProduct (axis:rest) = [ v:r | v <- axis, r <- crossProduct rest ]
答案 5 :(得分:1)
您可以通过两种方式实现这一目标:
cp :: [[a]] - &gt; [[α]]
cp [] = [[]]
cp(xs:xss)= [x:ys | x&lt; -xs,ys&lt; -cp xss]
cp1 :: [[a]] - &gt; [[α]]
cp1 xs = foldr f [[]] xs
where f xs xss = [x:ys | x <- xs, ys <- xss]