subsequences of length n from list performance

前端 未结 4 577
借酒劲吻你
借酒劲吻你 2020-12-05 22:07

I implemented a version of this answer https://stackoverflow.com/a/9920425/1261166 (I don\'t know what was intended by the person answering)

sublistofsize 0          


        
4条回答
  •  旧时难觅i
    2020-12-05 22:44

    This is a 6 years old topic but i believe i have a code worth sharing here.

    The accepted answer by @Bergi is just super but still i think this job can be done better as seen from two aspects;

    1. Although not mentioned in any of the specifications, it returns combinations in reverse lexicographical order. One might like to have them in lexicographical order as it is mostly the case.
    2. When tested with C(n,n/2) they perform similar however when tested like C(100,5) the following code is much faster and more memory efficient.

    .

    combinationsOf :: Int -> [a] -> [[a]]
    combinationsOf 1 as        = map pure as
    combinationsOf k as@(x:xs) = run (l-1) (k-1) as $ combinationsOf (k-1) xs
                                 where
                                 l = length as
    
                                 run :: Int -> Int -> [a] -> [[a]] -> [[a]]
                                 run n k ys cs | n == k    = map (ys ++) cs
                                               | otherwise = map (q:) cs ++ run (n-1) k qs (drop dc cs)
                                               where
                                               (q:qs) = take (n-k+1) ys
                                               dc     = product [(n-k+1)..(n-1)] `div` product [1..(k-1)]
    

    Lets compare them against the test case under the accepted answer.

    *Main> length $ subsequencesOfSize 7 [1..25]
    480700
    (0.27 secs, 145,572,672 bytes)
    
    *Main> length $ combinationsOf 7 [1..25]
    480700
    (0.14 secs, 95,055,360 bytes)
    

    Let us test them against something harder like C(100,5)

    *Main> length $ subsequencesOfSize 5 [1..100]
    75287520
    (52.01 secs, 77,942,823,360 bytes)
    
    *Main> length $ combinationsOf 5 [1..100]
    75287520
    (17.61 secs, 11,406,834,912 bytes)
    

提交回复
热议问题