我想制作具有2个列表的子组的所有可能组合。这是一个功能:
getCombinations :: [a] -> [[a]]
getCombinations na = do
a <- na
b <- na
[[a,b]]
如果将“abc”传递给此函数,则返回:
["aa","ab","ac","ba","bb","bc","ca","cb","cc"]
对同一方法的简单修改可以返回3个列表的组合,而不是两个。
getCombinations :: [a] -> [[a]]
getCombinations na = do
a <- na
b <- na
c <- na
[[a,b,c]]
将“abc”作为参数传递的结果:
["aaa","aab","aac","aba","abb","abc","aca","acb","acc",
"baa","bab","bac","bba","bbb","bbc","bca","bcb","bcc",
"caa","cab","cac","cba","cbb","cbc","cca","ccb","ccc"]
使其扩展到任意数量的列表的最简单方法是什么?以下是类型声明的样子:
getCombinations :: Int -> [a] -> [[a]]
答案 0 :(得分:27)
你想要的是replicateM
:
replicateM :: Int -> m a -> m [a]
定义很简单:
replicateM n = sequence . replicate n
所以在列表monad上sequence
正在这里做真正的工作。
答案 1 :(得分:18)
对于combination函数来到这里的人来说, k - 集合 S 的组合是<的一个子集em> k S 的不同元素,请注意订单并不重要。
从k
元素中选择n
元素等于从k - 1
元素中选择n - 1
元素,然后从k
元素中选择n - 1
元素。
使用这个递归定义,我们可以写:
combinations :: Int -> [a] -> [[a]]
combinations k xs = combinations' (length xs) k xs
where combinations' n k' l@(y:ys)
| k' == 0 = [[]]
| k' >= n = [l]
| null l = []
| otherwise = map (y :) (combinations' (n - 1) (k' - 1) ys) ++ combinations' (n - 1) k' ys
ghci> combinations 5 "abcdef"
["abcde","abcdf","abcef","abdef","acdef","bcdef"]
该问题是一个重复的排列,有人已经给出了答案。对于非重复排列,请使用Data.List中的permutations
。