背景:
我有一系列连续的,带时间戳的数据.数据序列中存在间隙,其中数据不连续.我想创建一种方法将序列分成序列序列,以便每个子序列包含连续数据(在间隙处分割输入序列).
约束:
方法签名
let groupContiguousDataPoints (timeBetweenContiguousDataPoints : TimeSpan) (dataPointsWithHoles : seq<DateTime * float>) : (seq<seq< DateTime * float >>)= ...
Run Code Online (Sandbox Code Playgroud)
从表面上看,问题看起来微不足道,但即使采用Seq.pairwise,IEnumerator <_>,序列理解和屈服声明,解决方案也让我望而却步.我确信这是因为我仍然缺乏组合F#-idioms的经验,或者可能是因为我还没有接触过一些语言结构.
// Test data
let numbers = {1.0..1000.0}
let baseTime = DateTime.Now
let contiguousTimeStamps = seq { for n in numbers ->baseTime.AddMinutes(n)}
let dataWithOccationalHoles = Seq.zip contiguousTimeStamps numbers |> Seq.filter (fun (dateTime, num) -> num % 77.0 <> 0.0) // Has a gap in the data every 77 items
let timeBetweenContiguousValues = (new TimeSpan(0,1,0))
dataWithOccationalHoles |> groupContiguousDataPoints timeBetweenContiguousValues |> Seq.iteri (fun i sequence -> printfn "Group %d has %d data-points: Head: %f" i (Seq.length sequence) (snd(Seq.hd sequence)))
Run Code Online (Sandbox Code Playgroud)
您似乎想要一个具有签名的函数
(`a -> bool) -> seq<'a> -> seq<seq<'a>>
Run Code Online (Sandbox Code Playgroud)
即一个函数和一个序列,然后根据函数的结果将输入序列分解为序列序列。
将值缓存到实现 IEnumerable 的集合中可能是最简单的(尽管不完全纯粹,但避免多次迭代输入。它将失去输入的大部分惰性):
让 groupBy (fun: 'a -> bool) (输入: seq) =
序列{
让缓存 = ref (new System.Collections.Generic.List())
for e 输入 do
(!cache).Add(e)
如果不是(有趣的e)那么
产量!缓存
缓存 := new System.Collections.Generic.List()
如果缓存.Length > 0 那么
产量!缓存
}
另一种实现可以将缓存集合(如seq<'a>)传递给函数,以便它可以看到多个元素来选择断点。