2014-02-14 46 views
4

我需要做同樣的事情爲itertools.combinations(iterable, r) in python從列表中得到k個元素的所有可能組合

到目前爲止,我想出了這樣一個功能:

{-| 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) 

是否有一個更優雅和高效解?通過採取nn

+0

請參閱[此答案](http://stackoverflow.com/a/8626006/98117)。 – hammar

+0

這很好,謝謝。我沒有找到它。 –

回答

4

(基於@ JoseJuan的答案)

您也可以使用列表解析來過濾掉那些第二個字符是比第一沒有嚴格較小:

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

'head(tail x)'可能會更清潔,因爲'x! 1'不? – jozefg

+1

@jozefg我認爲這是個人喜好的問題 - 你甚至可以寫x! 0

7

xs元件是

mapM (const xs) [1..n] 

所有組合(N = 1,2,...)是

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

如果需要沒有重複

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

然後

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

謝謝,但那不是我正在尋找的。 'mapM(const「ABCD」)[1..2]''返回'[「AA」,「AB」,「AC」,「AD」,「BA」,「BB」,「BC」,「BD」, 「CA」,「CB」,「CC」,「CD」,「DA」,「DB」,「DC」,「DD」]'不是'[「AB」,「AC」,「AD」 ((2 ==).length.nub)$ mapM(const「ABCD」)[1..2]''給出'[「AB」,「AC」,「BD」,「CD」]' –

+0

' , 「AD」, 「BA」, 「BC」, 「BD」, 「CA」, 「CB」, 「CD」, 「DA」, 「DB」, 「DC」]'。 ;-) –

+0

哎唷!你是對的! – josejuan

3

(基於on @ 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它)

相關問題