我正在尝试获取列表的所有组合。 [1,2,3]
的结果应为[(1,2),(1,3),(2,3)]
。但是,我在下面的实现提供了[(1,2),(2,3)]
。
parings [d] = []
parings (y:ys) = (y, head ys): parings ys
答案 0 :(得分:2)
9000答案中提到的列表理解可以简单地考虑到map
电话中。
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = map (\y -> (x, y)) xs ++ pairwise xs
每个列表理解都可以考虑到map
,filter
和concatMap
的某种组合,可能会散布一些let
个绑定。这样做是学习如何操作函数的好习惯。
答案 1 :(得分:1)
以下是使用tails
中的Data.List
的一个实现:
import Data.List
pairings :: [a] -> [(a, a)]
pairings = concatMap makePairs . tails
where
makePairs [] = []
makePairs (x:xs) = fmap ((,) x) xs
注意:
我不知道tails
是否算作特殊导入"对于你 - 尽管它不在Prelude中,它可以在 base 库中找到,它始终可用。
要了解tails
的作用,请尝试tails [1..3]
。
((,) x)
只是撰写(\y -> (x, y))
的简洁方式。如果您发现它很难看,您可以改为编写较长版本,或启用TupleSections
扩展名并将其拼写为(x,)
。
makePairs
可能在没有显式递归的情况下编写为......
makePairs = maybe [] (\(x, xs) -> fmap ((,) x) xs) . uncons
... uncons
中也可以找到Data.List
。
这里答案中的所有实现都有一个并非无关紧要的问题:它们在内存中保留了消耗的列表段。要查看我正在谈论的内容,请在GHCi中运行head . drop 8000000 $ pairings [1..]
时查看内存使用情况。我对此没有确凿的解决方法 - 例如,一个简单的concat . tails
似乎遇到了同样的问题,而fmap makePairs . tails
没有(甚至{{ 1}}不会吃掉你所有的记忆。
答案 2 :(得分:0)
我不知道你为什么反对列表理解;与他们一起,解决方案是微不足道的:
pairwise :: [a] -> [(a, a)]
pairwise [] = []
pairwise (x:xs) = [(x, y) | y <- xs] ++ pairwise xs
如果需要,可以将理解分解为具有显式尾递归的单独函数。
(通过保持++
两侧的参数并具有累加器参数,整个事物也可以进行尾递归。)