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
If you want to write efficient functional code, then it is a good idea to avoid using the @ operator, because concatentation of lists is very inefficient.
Here is an example of how you can write a function to generate all combinations:
let rec combinations acc size set = seq {
match size, set with
| n, x::xs ->
if n > 0 then yield! combinations (x::acc) (n - 1) xs
if n >= 0 then yield! combinations acc n xs
| 0, [] -> yield acc
| _, [] -> () }
combinations [] 3 [1 .. 4]
The parameters of the function are:
acc is used to remember elements that are already selected to be included in the combination (initially this is an empty list)size is the remaining number of elements that we need to add to acc (initially this is the required size of the combinations)set is the set elements to choose fromThe function is implemented using a simple recursion. If we need to generate combinations of size n then we can either add or don't add the current element, so we try to generate combinations using both options (first case) and add all of them to the generated sequence using yield!. If we need 0 more elements, then we successfuly generated a combination (second case) and if we end with some other number but don't have any remaining elements to use then we cannot return anything (last case).
Combinations with repetition would be similar - the difference is that you don't need to remove the elements from the list (by using just xs in the recursive calls) so there are more options of what to do.