I only started programming in F# yesterday, so I've not yet discovered what idiomatic F# actually looks like.
The first task I set myself required partitioning a list into smaller lists but where the partitioning is based on the characteristics of the whole group, rather than just being able to find split points based on the current element.
For example, given the list
[1;2;3;4;5], I might want to group into sub-lists when the sum of the sub-list has reached at least 5. This would result in the output
Any remaining elements that don't meet the criteria would be in a final sub-list.
My first attempt is below:
module Test let rec partitionOn groupComplete list = let take list n = Seq.take n list // Take items from the front of the list until they form a complete group // or there are no more items let firstGroupAndRemainder itemsList = let firstGroup = [0 .. List.length itemsList] |> Seq.map (take itemsList) |> Seq.tryFind groupComplete match firstGroup with | Some g -> let groupList = g |> Seq.toList let remainingList = Seq.skip (List.length groupList) itemsList |> Seq.toList (groupList, remainingList) | None -> (itemsList, ) match list with |  ->  | _ -> let group, rest = firstGroupAndRemainder list [group] @ partitionOn groupComplete rest [<EntryPoint>] let main argv = // Groups with sum greater than 5 (plus remaining elements) let result1 = partitionOn (fun l -> Seq.sum l > 5) [1;5;2;6;2] printfn "result1: %A" result1 // [[1;5]; [2;6]; ] // Groups with length 3 (plus remaining elements) let result2 = partitionOn (fun l -> Seq.length l = 3) [1;5;2;6;2] printfn "result2: %A" result2 // [[1;5;2]; [6;2]] 0
It feels like there should be a simpler way to achieve this but I haven't yet thought of it.
I've discovered the
defaultArg function, so the
firstGroupAndRemainder function might be slightly tidier as:
let firstGroupAndRemainder itemsList = let firstGroup = [0 .. List.length itemsList] |> Seq.map (take itemsList) |> Seq.tryFind groupComplete let groupList = (defaultArg firstGroup (List.toSeq itemsList)) |> Seq.toList let remainingList = Seq.skip (List.length groupList) itemsList |> Seq.toList (groupList, remainingList)