Haskell: comparison of techniques for generating combinations

后端 未结 2 641
天涯浪人
天涯浪人 2020-12-10 18:12

I was doing a few of the 99 Haskell Problems earlier and I thought that exercise 27 (\"write a function to enumerate the possible combinations\") was interestin

相关标签:
2条回答
  • 2020-12-10 18:31
    fact :: (Integral a) => a -> a
    fact n = product [1..n]
    
    ncombs n k = -- to evaluate number of combinations
        let n' = toInteger n
            k' = toInteger k
        in div (fact n') ((fact k') * (fact (n' - k')))
    
    combinations :: Int -> [a] -> [[a]]
    combinations 0 xs = [[]]
    combinations 1 xs = [[x] | x <- xs]
    combinations n xs =
        let ps = reverse [0..n - 1]
            inc (p:[])
                | pn < length xs = pn:[]
                | otherwise = p:[]
                where pn = p + 1
            inc (p:ps)
                | pn < length xs = pn:ps
                | (head psn) < length xs = inc ((head psn):psn)
                | otherwise = (p:ps)
                where pn = p + 1
                      psn = inc ps
            amount = ncombs (length xs) n
            pointers = take (fromInteger amount) (iterate inc ps)
            c' xs ps = map (xs!!) (reverse ps)
        in map (c' xs) pointers
    

    I am learning Haskell and found a comparably fast implementation. I had a hard time with the type system with some functions requiring Ints and some fractional numbers and some Integers. On my computer the fastest solution presented here takes about 6,1 seconds to run and mine takes 3,5 to 2,9 seconds.

    0 讨论(0)
  • 2020-12-10 18:48

    You should also test the algorithm found in this SO answer:

    subsequences of length n from list performance

    subsequencesOfSize :: Int -> [a] -> [[a]]
    subsequencesOfSize n xs = let l = length xs
                              in if n>l then [] else subsequencesBySize xs !! (l-n)
     where
       subsequencesBySize [] = [[[]]]
       subsequencesBySize (x:xs) = let next = subsequencesBySize xs
                                 in zipWith (++) ([]:next) (map (map (x:)) next ++ [[]])
    

    On my machine I get the following timing and memory usage from ghci:

    ghci> length $ combSoln7   13 "abcdefghijklmnopqrstuvwxyz"
    10400600
    (13.42 secs, 10783921008 bytes)
    
    ghci> length $ subsequencesOfSize  13 "abcdefghijklmnopqrstuvwxyz"
    10400600
    (6.52 secs, 2889807480 bytes)
    
    0 讨论(0)
提交回复
热议问题