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

Tob*_*ann 5 haskell combinatorics

我需要一个与python相同的功能itertools.combinations(iterable, r)

到目前为止,我想出了这个:

{-| 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)
Run Code Online (Sandbox Code Playgroud)

有更优雅和有效的解决方案吗?

jos*_*uan 8

xs采取n的元素n

mapM (const xs) [1..n]
Run Code Online (Sandbox Code Playgroud)

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

allCombs xs = [1..] >>= \n -> mapM (const xs) [1..n]
Run Code Online (Sandbox Code Playgroud)

如果你需要不重复

filter ((n==).length.nub)
Run Code Online (Sandbox Code Playgroud)

然后

combinationsWRep xs n = filter ((n==).length.nub) $ mapM (const xs) [1..n]
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,但这不是我要找的。`mapM (const "ABCD") [1..2]` 返回 `["AA","AB","AC","AD","BA","BB","BC","BD", "CA","CB","CC","CD","DA","DB","DC","DD"]` 不是 `["AB","AC","AD","BC ","BD","CD"]` (2认同)

Fra*_*itt 6

(基于@JoseJuan 的回答)

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

[x| x <- mapM (const "ABCD") [1..2], head x < head (tail x) ]
Run Code Online (Sandbox Code Playgroud)

  • @jozefg 我认为这是个人喜好问题-您甚至可以写 x !!0 &lt; x !! 1. 对我来说,来自命令式背景,使用 x !! 1 意味着它是一个 O(1) 操作,而对于 Haskell 列表,它是 O(n)。另一方面,head (tail x) 清楚地告诉我我正在对一个链表执行两个操作。 (3认同)