// This is the refactored version following comments by mjolka here: http://codereview.stackexchange.com/a/55606/4813 // Here are the "lines" from my "log file". let lines = [1 .. 25] |> List.map (fun x -> x.ToString()) // For this exercise, section criteria is divisibility by 5. // val DivisibleByFive : s:string -> bool let DivisibleByFive (s:string) = System.Int32.Parse(s) % 5 = 0 // I am going to use the following type to hold the information // from each section of the log. type Section (lines:string list) = member x.Lines = lines /// /// Splits the given sequence into non-empty contiguous subsequences, such /// that the last element of every subsequence (except possibly the last) /// satisfies the given predicate. No other elements satisfy the predicate. /// /// /// /// let even x = x % 2 = 0 /// printfn "%A" (splitAtEach even (seq { 1 .. 3 })) /// printfn "%A" (splitAtEach even (seq { 1 .. 4 })) /// /// The output is: /// /// seq [[1; 2]; [3]] /// seq [[1; 2]; [3; 4]] /// /// let splitAtEach (predicate : 'T -> bool) (xs : seq<'T>) : seq<'T list> = let section = new ResizeArray<'T>() seq { for x in xs do section.Add x if predicate x then yield Seq.toList section section.Clear() if section.Any() then yield Seq.toList section } let sections = splitAtEach DivisibleByFive lines |> Seq.map (fun lines -> new Section(lines)) |> Seq.toList printfn "Parsed %d section from the log:" sections.Length sections |> List.iter (fun section -> printfn " Section starting with %s" section.Lines.[0])