3 people like it.

Group elements of a sequence by time windows of fixed intervals

Function that associates a time window with each element of a sequence. The resulting sequence can then be grouped by the time windows for further processing

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
open System

let withTimeWindow<'T> (fnTime:'T-> DateTime) (window:TimeSpan) (xs:'T seq) =
    let xs' = xs |> Seq.sortBy fnTime
    let tFrom = xs' |> Seq.head |> fnTime
    let tTo = tFrom.AddSeconds(window.TotalSeconds)
    let ixs = xs'.GetEnumerator()

    let rec nxt(f:DateTime,t) prevX = 
        seq {
            let x = 
                prevX 
                |> Option.map(fun _ -> prevX)
                |> Option.defaultWith(fun () -> if ixs.MoveNext() then Some(ixs.Current) else None)
            match x with
            | Some x -> 
                let tx = fnTime x
                if tx < t then
                    yield ((f,t),x)
                    yield! nxt (f,t) None
                else
                    let f = f.AddSeconds(window.TotalSeconds)
                    let t = t.AddSeconds(window.TotalSeconds)
                    yield! nxt (f,t) (Some x)
            | None -> ixs.Dispose()
        }
        
    nxt (tFrom,tTo) None 

(*
let xs = seq{for i in 0 .. 100 -> i } |> Seq.scan (fun ((s:DateTime),_) t -> s.AddMinutes(1.0),t) (DateTime.Now,0)
let wxs = xs |> withTimeWindow fst (TimeSpan.FromMinutes 5.)
let wsg = wxs |> Seq.groupBy fst |> Seq.map (fun (interval,xs)->interval,Seq.length xs) |> Seq.toArray
> 
val wsg : ((DateTime * DateTime) * int) [] =
  [|((8/26/2020 4:36:01 PM, 8/26/2020 4:41:01 PM), 5);
    ((8/26/2020 4:41:01 PM, 8/26/2020 4:46:01 PM), 5);
    ((8/26/2020 4:46:01 PM, 8/26/2020 4:51:01 PM), 5);
    ((8/26/2020 4:51:01 PM, 8/26/2020 4:56:01 PM), 5);
    ((8/26/2020 4:56:01 PM, 8/26/2020 5:01:01 PM), 5);
    ((8/26/2020 5:01:01 PM, 8/26/2020 5:06:01 PM), 5);
    ((8/26/2020 5:06:01 PM, 8/26/2020 5:11:01 PM), 5);
    ((8/26/2020 5:11:01 PM, 8/26/2020 5:16:01 PM), 5);
    ((8/26/2020 5:16:01 PM, 8/26/2020 5:21:01 PM), 5);
    ((8/26/2020 5:21:01 PM, 8/26/2020 5:26:01 PM), 5);
    ((8/26/2020 5:26:01 PM, 8/26/2020 5:31:01 PM), 5);
    ((8/26/2020 5:31:01 PM, 8/26/2020 5:36:01 PM), 5);
    ((8/26/2020 5:36:01 PM, 8/26/2020 5:41:01 PM), 5);
    ((8/26/2020 5:41:01 PM, 8/26/2020 5:46:01 PM), 5);
    ((8/26/2020 5:46:01 PM, 8/26/2020 5:51:01 PM), 5);
    ((8/26/2020 5:51:01 PM, 8/26/2020 5:56:01 PM), 5);
    ((8/26/2020 5:56:01 PM, 8/26/2020 6:01:01 PM), 5);
    ((8/26/2020 6:01:01 PM, 8/26/2020 6:06:01 PM), 5);
    ((8/26/2020 6:06:01 PM, 8/26/2020 6:11:01 PM), 5);
    ((8/26/2020 6:11:01 PM, 8/26/2020 6:16:01 PM), 5);
    ((8/26/2020 6:16:01 PM, 8/26/2020 6:21:01 PM), 2)|]
*)
namespace System
val withTimeWindow : fnTime:('T -> DateTime) -> window:TimeSpan -> xs:seq<'T> -> seq<(DateTime * DateTime) * 'T>
val fnTime : ('T -> DateTime)
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

--------------------
DateTime ()
   (+0 other overloads)
DateTime(ticks: int64) : DateTime
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
val window : TimeSpan
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Divide : divisor:float -> TimeSpan + 1 overload
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    ...
  end

--------------------
TimeSpan ()
TimeSpan(ticks: int64) : TimeSpan
TimeSpan(hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : TimeSpan
val xs : seq<'T>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>
val xs' : seq<'T>
module Seq

from Microsoft.FSharp.Collections
val sortBy : projection:('T -> 'Key) -> source:seq<'T> -> seq<'T> (requires comparison)
val tFrom : DateTime
val head : source:seq<'T> -> 'T
val tTo : DateTime
val ixs : Collections.Generic.IEnumerator<'T>
val nxt : (DateTime * DateTime -> 'T option -> seq<(DateTime * DateTime) * 'T>)
val f : DateTime
val t : DateTime
val prevX : 'T option
val x : 'T option
module Option

from Microsoft.FSharp.Core
val map : mapping:('T -> 'U) -> option:'T option -> 'U option
val defaultWith : defThunk:(unit -> 'T) -> option:'T option -> 'T
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val x : 'T
val tx : DateTime
Next Version Raw view Test code New version

More information

Link:http://fssnip.net/7YE
Posted:4 years ago
Author:Faisal Waris
Tags: timespan , windowed , #seq