12 people like it.

Chronological sequence window beginnings

An abstraction of the following use case: Given a sequence of dates and max temperatures for each date, extract out the initial dates on which the temp is greater than a given threshold for n consecutive days. (Originally posted as an answer to this StackOverflow question: http://stackoverflow.com/questions/5267055 )

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
let findWindowBeginnings predicate minWindowSize data =
    if minWindowSize < 2 then invalidArg "minWindowSize" "minWindowSize must be greater than 1"
    ((None, []), data)
    ||> Seq.fold (fun (window, acc) x ->
        if predicate x then
            match window with
            | Some (start, size) -> let size' = size + 1
                                    let acc' = if size' = minWindowSize then start::acc else acc
                                    Some (start, size'), acc'
            | _                  -> Some (x, 1), acc
        else None, acc)
    |> snd
    |> List.rev

// example usage, implementing described use case:
let findHeatwaveBeginnings tempThreshold consecutiveDays data =
    (consecutiveDays, data)
    ||> findWindowBeginnings (snd >> (<) tempThreshold)
    // alternatively, if one isn't a fan of point-free style code:
    //  findWindowBeginnings (fun (_, maxTemp) -> maxTemp > tempThreshold)
    |> List.map fst
val findWindowBeginnings : predicate:('a -> bool) -> minWindowSize:int -> data:seq<'a> -> 'a list

Full name: Script.findWindowBeginnings
val predicate : ('a -> bool)
val minWindowSize : int
val data : seq<'a>
val invalidArg : argumentName:string -> message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.invalidArg
union case Option.None: Option<'T>
module Seq

from Microsoft.FSharp.Collections
val fold : folder:('State -> 'T -> 'State) -> state:'State -> source:seq<'T> -> 'State

Full name: Microsoft.FSharp.Collections.Seq.fold
val window : ('a * int) option
val acc : 'a list
val x : 'a
union case Option.Some: Value: 'T -> Option<'T>
val start : 'a
val size : int
val size' : int
val acc' : 'a list
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val rev : list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.rev
val findHeatwaveBeginnings : tempThreshold:'a -> consecutiveDays:int -> data:seq<'b * 'a> -> 'b list (requires comparison)

Full name: Script.findHeatwaveBeginnings
val tempThreshold : 'a (requires comparison)
val consecutiveDays : int
val data : seq<'b * 'a> (requires comparison)
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst

More information

Link:http://fssnip.net/3u
Posted:6 years ago
Author:ildjarn
Tags: sequence , window , fold