Combinations and Permutations in F#

后端 未结 3 940
北荒
北荒 2020-12-13 11:23

I\'ve recently written the following combinations and permutations functions for an F# project, but I\'m quite aware they\'re far from optimised.

/// Rotates         


        
3条回答
  •  囚心锁ツ
    2020-12-13 11:47

    I noticed that your updated getPerms function contains duplicates. Here's my crack at a dupe-free version. Hopefully the comments speak for themselves. The hardest part was writing an efficient distrib function, because the concatenation operator has to be used somewhere. Luckily it's only used on small sublists, so the performance remains reasonable. My getAllPerms code below generates all permutations of [1..9] in around a quarter of a second, all 10-element permutations in around 2.5 seconds.

    Edit: funny, I didn't look at Tomas' code, but his combinations function and my picks function are nearly identical.

    // All ordered picks {x_i1, x_i2, .. , x_ik} of k out of n elements {x_1,..,x_n}
    // where i1 < i2 < .. < ik
    let picks n L = 
        let rec aux nleft acc L = seq {
            match nleft,L with
            | 0,_ -> yield acc
            | _,[] -> ()
            | nleft,h::t -> yield! aux (nleft-1) (h::acc) t
                            yield! aux nleft acc t }
        aux n [] L
    
    // Distribute an element y over a list:
    // {x1,..,xn} --> {y,x1,..,xn}, {x1,y,x2,..,xn}, .. , {x1,..,xn,y}
    let distrib y L =
        let rec aux pre post = seq {
            match post with
            | [] -> yield (L @ [y])
            | h::t -> yield (pre @ y::post)
                      yield! aux (pre @ [h]) t }
        aux [] L
    
    // All permutations of a single list = the head of a list distributed
    // over all permutations of its tail
    let rec getAllPerms = function
        | [] -> Seq.singleton []
        | h::t -> getAllPerms t |> Seq.collect (distrib h)
    
    // All k-element permutations out of n elements = 
    // all permutations of all ordered picks of length k combined
    let getPerms2 n lst = picks n lst |> Seq.collect getAllPerms
    

    Edit: more code in response to comments

    // Generates the cartesian outer product of a list of sequences LL
    let rec outerProduct = function
        | [] -> Seq.singleton []
        | L::Ls -> L |> Seq.collect (fun x -> 
                    outerProduct Ls |> Seq.map (fun L -> x::L))
    
    // Generates all n-element combination from a list L
    let getPermsWithRep2 n L = 
        List.replicate n L |> outerProduct  
    

提交回复
热议问题