两个列表元素的所有非重复组合

时间:2019-01-23 22:07:17

标签: haskell

使用示例更容易解释这一点:

我想编写一个函数[a]-> [(a,a)],以便获得列表

[A, B, C, D] 

我希望此列表返回:

[(A, A), (A,B), (A,C), (A,D), (B,B), (B,C), (B,D), (C,C), (C,D), (D,D)]

我想到了以下代码:

function s = [(x,y) | x <- s, y <- s, x<=y]

这对于整数列表可以正常工作,但是我希望它对不是Ord类实例的数据类型起作用。我的数据类型派生Show和Eq。有没有简单的方法可以解决这个问题?我在想也许是通过过滤

中的元组
function s = [(x,y) | x <- s, y <- s]

但是我也不知道该怎么做。

4 个答案:

答案 0 :(得分:5)

使用递归的解决方案:

f :: [a] -> [(a, a)]
f []     = []
f (x:xs) = [(x, y) | y <- (x:xs)] ++ f xs 

无递归:

import Data.List (tails) 

f' :: [a] -> [(a, a)]
f' xs = concat [[(head x, y) | y <- x] | x <- tails xs]

没有列表理解:

import Data.List (tails) 

f'' :: [a] -> [(a, a)]
f'' xs = concatMap (\sl -> zip (repeat $ head sl) sl) (tails xs)

最好的是丹尼尔·瓦格纳(Daniel Wagner),只需使用

[(head x, y) | x <- tails xs, y <- x]

答案 1 :(得分:2)

这是一个嵌套循环。

import Data.List (dropWhile)

com xs = do
  x <- xs
  y <- dropWhile (/= x) xs
  return (x, y)

答案 2 :(得分:1)

您可以使用scanr

f l = zip l (scanr (:) [] l) >>= \(h,t) -> fmap ((,) h) t

首先,您将获得l的(头,尾)列表,将图尾与相应的头配对的图尾,最后将所有内容展平。

答案 3 :(得分:0)

继续使用过滤器[(x,y) | x <- xs, y <- xs]的想法,您可以使用foldl代替:

f = foldl add [] 
  where add ys (a,b) | notElem (b,a) ys = (a,b):ys 
                     | otherwise = ys

g xs = [(x,y) | x <- xs, y <- xs]

function = f . g