The general idea would be this: for each element x of the list, produce a list of x-combinations by combining it with every element y that comes after x in the list.
To do this, you'd need to index the elements, so you can compare them in terms of coming before/after each other. For this you can use the List.indexed function:
let lst = [1;2;3;4]
let indexedLst = List.indexed lst
// indexedLst = [(0,1); (1,2); (2,3); (3,4)]
After we have the elements indexed, we can pick one element (together with its index) and produce a list of combinations of that element with every other element that comes after it:
let combineWithSuccessors (x_idx, x) =
[ for y_idx, y in indexedLst do
if y_idx > x_idx then yield (x, y) ]
// Or if you prefer not using list comprehensions:
let combineWithSuccessors (x_idx, x) =
indexedLst
|> List.filter (fun (y_idx, _) -> y_idx > x_idx)
|> List.map (fun (_, y) -> (x, y))
// test it out:
combineWithSuccessors (2, 3) == [(3,4)]
combineWithSuccessors (0, 1) == [(1,2); (2,3); (3,4)]
Finally, generate such combinations list for every x, and concatenate all these lists in one:
let allCombinations =
indexedLst |> List.map combineWithSuccessors |> List.concat
And then put it all together:
let allCombinations lst =
let indexedLst = List.indexed lst
let combineWithSuccessors (x_idx, x) =
[ for y_idx, y in indexedLst do
if y_idx > x_idx then yield (x, y) ]
indexedLst |> List.map combineWithSuccessors |> List.concat
Test it out:
allCombinations [1;2;3;4;5]
> [(1, 2); (1, 3); (1, 4); (1, 5); (2, 3); (2, 4); (2, 5); (3, 4); (3, 5); (4, 5)]
allCombinations [5;7;1;2;3]
> [(5, 7); (5, 1); (5, 2); (5, 3); (7, 1); (7, 2); (7, 3); (1, 2); (1, 3); (2, 3)]