Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally apply filter in forward pipe chain in F#?

I get a sequence of records from a CSV file. I want to optionally filter those records by date and type and optionally consolidate records meeting certain criteria. Optionally filtering by date and type is straightforward using Seq.filter. However I would like to optionally consolidate records meeting certain criteria. I have the function working, I just can't figure out how to optionally apply it to the resulting sequence. I can't use Seq.filter because consolidate operates on the entire sequence not on one item at a time. I can solve it with an intermediate variable, I was just wondering if there was a graceful idiomatic way to handle this.

Basically I want to know a way to conditionally apply one (or more) parts of the chain in a forward pipe sequence.

This is what I want in pseudo code (options holds command line parameters):

let x =
    getRecords options.filePath
    |> Seq.filter (fun r -> if options.Date.HasValue then
                            r.Date.Date = options.Date.Value.Date else true)
    |> Seq.filter (fun r -> if not(String.IsNullOrEmpty(options.Type)) then
                            r.Type = options.Type else true)
    if options.ConsolidateRecords then
        |> consolidateRecords
like image 793
User Avatar asked Jul 23 '13 23:07

User


3 Answers

You can use an if ... else expression with the identity function in else clause:

let x =
    getRecords options.filePath
    |> (* ... bunch of stuff ... *)
    |> (if options.ConsolidateRecords then consolidateRecords else id)
    |> (* ... optionally more stuff ... *)
like image 67
MisterMetaphor Avatar answered Nov 15 '22 11:11

MisterMetaphor


I would do something like

let x =
    getRecords options.filePath
    |> Seq.filter (fun r -> if options.Date.HasValue then
                            r.Date.Date = options.Date.Value.Date else true)
    |> Seq.filter (fun r -> if not(String.IsNullOrEmpty(options.Type)) then
                            r.Type = options.Type else true)
    |> fun x ->
         if options.ConsolidateRecords then x |> consolidateRecords
         else ....
like image 35
John Palmer Avatar answered Nov 15 '22 10:11

John Palmer


You could also shadow the previous definition of x:

let x =
    getRecords options.filePath
    |> Seq.filter (fun r -> 
        not options.Date.HasValue || r.Date.Date = options.Date.Value.Date)
    |> Seq.filter (fun r -> 
        String.IsNullOrEmpty(options.Type) || r.Type = options.Type)
let x = if options.ConsolidateRecords then consolidateRecords x else x
like image 33
Daniel Avatar answered Nov 15 '22 12:11

Daniel