Skip to content

Instantly share code, notes, and snippets.

@seankearon
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seankearon/20d6b0c1c0e10bbd13dd to your computer and use it in GitHub Desktop.
Save seankearon/20d6b0c1c0e10bbd13dd to your computer and use it in GitHub Desktop.
Parsing sections from a log file using F#
// Code for review posted here: http://codereview.stackexchange.com/questions/55554/parsing-sections-from-a-log-file-using-f
// 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
// Read a single section from the top of the log (based on: http://fssnip.net/iV).
// val GetSection : lines:string list -> Section * string list
let GetSection (lines:string list) =
let rec getSection (l:string list) result =
match l with
| h::t when DivisibleByFive h ->
let values = h::result |> List.rev
(new Section(values), t)
| h::t when not (DivisibleByFive h) ->
getSection t (h::result)
| _ ->
(new Section(result), [])
getSection lines []
// Get a list of all sections from the log.
// val GetSections : lines:string list -> Section list
let GetSections (lines:string list) =
let rec getSections (l:string list) result =
match GetSection l with
| (a, []) -> (a::result)
| (a, b) -> getSections b (a::result)
getSections lines [] |> List.rev
let sections = GetSections lines
sprintf "Parsed %d section from the log:" sections.Length |> System.Console.WriteLine
for i in sections do
sprintf " Section starting with %s" i.Lines.[0] |> System.Console.WriteLine
// 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
/// <summary>
/// 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.
/// </summary>
/// <example>
/// <c>
/// let even x = x % 2 = 0
/// printfn "%A" (splitAtEach even (seq { 1 .. 3 }))
/// printfn "%A" (splitAtEach even (seq { 1 .. 4 }))
/// </c>
/// The output is:
/// <c>
/// seq [[1; 2]; [3]]
/// seq [[1; 2]; [3; 4]]
/// </c>
/// </example>
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])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment