F#:我如何将序列分成序列序列

Tre*_*rog 10 f# sequences

背景:

我有一系列连续的,带时间戳的数据.数据序列中存在间隙,其中数据不连续.我想创建一种方法将序列分成序列序列,以便每个子序列包含连续数据(在间隙处分割输入序列).

约束:

  • 返回值必须是序列序列,以确保元素仅在需要时生成(不能使用列表/数组/缓存)
  • 解决方案不能是O(n ^ 2),可能排除Seq.take - Seq.skip模式(参见Brian的帖子)
  • 功能惯用方法的奖励点(因为我希望在功能编程方面更加精通),但这不是必需的.

方法签名

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)

Ric*_*ard 1

您似乎想要一个具有签名的函数

(`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>)传递给函数,以便它可以看到多个元素来选择断点。