比如说我有一个像这样的列表
list = ["AC", "BA"]
我想将此列表的每个唯一组合添加到元组中,因此结果如下:
[("AC", "AC"),("AC","BA"),("BA", "BA")]
其中("BA","AC")
被排除在外。
我的第一种方法是使用这样的列表理解:
ya = [(x,y) | x <- list, y <- list]
但我无法让它发挥作用,无论如何通过使用列表推导来实现我的结果?
答案 0 :(得分:8)
我首选的解决方案使用列表理解
f :: [t] -> [(t, t)]
f list = [ (a,b) | theTail@(a:_) <- tails list , b <- theTail ]
我觉得这很可读:首先你选择(非确定性地)后缀theTail
,从a
开始,然后你选择(非确定性地)一个元素{{1}后缀。最后,生成了b
对,它明显超出了所需的对。
它也应该是最佳效率的:每当你需要一个元素时,就会产生恒定的时间。
答案 1 :(得分:7)
ThreeFx的答案将起作用,但它会增加您必须可订购元素的约束。相反,您可以使用Prelude
和Data.List
中的函数来更有效,更通用地实现此功能:
import Data.List (tails)
permutations2 :: [a] -> [(a, a)]
permutations2 list
= concat
$ zipWith (zip . repeat) list
$ tails list
它不使用列表推导,但它无需执行可能代价高昂的比较,也不会对可以通过它进行何种类型的值进行任何限制。
要了解其工作原理,请考虑如果您拥有列表[1, 2, 3]
,那么您就拥有了这些组
[(1, 1), (1, 2), (1, 3),
(2, 2), (2, 3),
(3, 3)]
这相当于
[(1, [1, 2, 3]),
(2, [2, 3]),
(3, [3])]
因为它不包含任何额外或更少的信息。从此表单到我们所需输出的转换是将函数f (x, ys) = map (\y -> (x, y)) ys
映射到每个元组,然后将concat
映射到一起。现在我们只需要弄清楚如何获得这些元组的第二个元素。很明显,我们看到它所做的一切都是从列表前面删除连续的元素。幸运的是,tails
中的Data.List
函数已经为我们实现了这一点。每个元组中的第一个元素只构成原始列表,因此我们知道可以使用zip
。最初,您可以使用
> concatMap (\(x, ys) -> map (\y -> (x, y)) ys) $ zip list $ tails list
但我个人更喜欢zip
,所以我将内部函数转换为不必使用lambdas的函数:
> concatMap (\(x, ys) -> zip (repeat x) ys) $ zip list $ tails list
由于我更喜欢zipWith f
而不是map (uncurry f) . zip
,我将此转为
> concat $ zipWith (\x ys -> zip (repeat x) ys) list $ tails list
现在,我们可以进一步减少这种情况:
> concat $ zipWith (\x -> zip (repeat x)) list $ tails list
> concat $ zipWith (zip . repeat) list $ tails list
感谢eta减少和功能组成。
我们可以把它完全放在哪里> permutations2 = concat . ap (zipWith (zip . repeat)) tails
但我发现这很难阅读和理解,所以我认为我会坚持使用以前的版本。
答案 2 :(得分:3)
只需使用列表理解:
f :: (Ord a) => [a] -> [(a, a)]
f list = [ (a, b) | a <- list, b <- list, a <= b ]
由于Haskell的String
位于Ord
类型类中,这意味着它可以被排序,因此首先告诉Haskell获取所有可能的组合,然后排除{{1}中的每个组合。 }大于b
,删除所有&#34;重复&#34;组合
示例输出:
a