计算 n 元笛卡尔积

发布于 2024-09-12 14:57:23 字数 761 浏览 2 评论 0原文

给定两个列表,我可以生成所有排列的列表这两个列表的笛卡尔积:

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 列表版本本质上是 笛卡尔积,但我可以'我的注意力集中在实现n 元笛卡尔积。有什么指点吗?

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 :: [[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.

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. Any pointers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

荒路情人 2024-09-19 14:57: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]]
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]]
同尘 2024-09-19 14:57:23

我找到了 Eric Lippert 的文章 使用 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 非常相似。

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.

傻比既视感 2024-09-19 14:57:23

这是我简单地实现它的方法,仅使用列表理解。

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

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 ]
失退 2024-09-19 14:57:23

作为 jleedev 答案的补充(无法在评论中格式化):

单子函数的快速未经检查的替换:

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

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
就此别过 2024-09-19 14:57:23

如果你想对输出有更多的控制,你可以使用列表作为应用函子,例如:

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

假设你想要一个元组列表:

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

而且它看起来也很酷......

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]) <
gt;  [1,2]­ <*> [4,5]­ <*> [6,7]

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

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

And it looks kind of cool, too...

要走干脆点 2024-09-19 14:57:23

您可以通过两种方式执行此操作:

  1. 使用列表理解
 cp :: [[a]] -> cp :: [[a]] -> [[一个]]
  cp [] = [[]]
  cp (xs:xss) = [ x:ys | x <- xs, ys <- cp xss ]
  1. 使用折叠
 cp1 :: [[a]] -> cp1 :: [[a]] -> [[一个]]
  cp1 xs = 折叠 f [[]] xs
        其中 f xs xss = [x:ys | x <- xs, ys <- xss]

You can do this 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]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文