获取列表中k个元素的所有可能组合

时间:2014-02-14 09:24:28

标签: haskell combinatorics

我需要一个与itertools.combinations(iterable, r) in python

完全相同的功能

到目前为止,我提出了这个问题:

{-| forward application -}
x -: f = f x
infixl 0 -:

{-| combinations 2 "ABCD" = ["AB","AC","AD","BC","BD","CD"] -}
combinations :: Ord a => Int -> [a] -> [[a]]
combinations k l = (sequence . replicate k) l -: map sort -: sort -: nub
    -: filter (\l -> (length . nub) l == length l)

是否有更优雅高效的解决方案?

4 个答案:

答案 0 :(得分:7)

xs n nmapM (const xs) [1..n] 元素

allCombs xs = [1..] >>= \n -> mapM (const xs) [1..n]

所有组合(n = 1,2,...)

filter ((n==).length.nub)

如果你需要不重复

combinationsWRep xs n = filter ((n==).length.nub) $ mapM (const xs) [1..n]

然后

{{1}}

答案 1 :(得分:4)

(根据@JoseJuan的回答)

您还可以使用列表推导来过滤掉第二个字符并不严格小于第一个字符的列表:

[x| x <- mapM (const "ABCD") [1..2], head x < head (tail x) ]

答案 2 :(得分:4)

(根据@ FrankSchmitt的回答)

我们有map (const x) [1..n] == replicate n x所以我们可以将答案改为

[x| x <- sequence (replicate 2 "ABCD"), head x < head (tail x) ]

虽然在原始问题中,2是参数k,但对于此特定示例,可能不希望使用2复制并写入

[ [x1,x2] | x1 <- "ABCD", x2 <- "ABCD", x1 < x2 ]

代替。

使用参数k如果你想生成没有重复的东西,事情会有点棘手。我会递归地做:

f 0 _  = [[]]
f _ [] = []
f k as = [ x : xs | (x:as') <- tails as, xs <- f (k-1) as' ]

(如果列表中已有as,则此变体不会删除重复项;如果您担心它们,请将nub as传递给它

答案 3 :(得分:3)

这个答案:

subsequences of length n from list performance

是我见过的问题的最快解决方案。