F#:如何将一个序列拆分为一系列序列 [英] F#: How do i split up a sequence into a sequence of sequences

查看:39
本文介绍了F#:如何将一个序列拆分为一系列序列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:

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

I have a sequence of contiguous, time-stamped data. The data-sequence has gaps in it where the data is not contiguous. I want create a method to split the sequence up into a sequence of sequences so that each subsequence contains contiguous data (split the input-sequence at the gaps).

限制条件:

  • 返回值必须是一个序列序列,以确保元素只在需要时产生(不能使用列表/数组/缓存)
  • 解决方案不能是 O(n^2),可能排除了 Seq.take - Seq.skip 模式(参见 Brian 的 帖子)
  • 函数式惯用方法的加分项(因为我想更精通函数式编程),但这不是必需的.
  • The return value must be a sequence of sequences to ensure that elements are only produced as needed (cannot use list/array/cacheing)
  • The solution must NOT be O(n^2), probably ruling out a Seq.take - Seq.skip pattern (cf. Brian's post)
  • Bonus points for a functionally idiomatic approach (since I want to become more proficient at functional programming), but it's not a requirement.

方法签名

let groupContiguousDataPoints (timeBetweenContiguousDataPoints : TimeSpan) (dataPointsWithHoles : seq<DateTime * float>) : (seq<seq< DateTime * float >>)= ... 

从表面上看,这个问题对我来说似乎微不足道,但即使使用 Seq.pairwise、IEnumerator<_>、序列理解和 yield 语句,我也无法解决这个问题.我确信这是因为我仍然缺乏结合 F# 习惯用法的经验,或者可能是因为我还没有接触过一些语言结构.

On the face of it the problem looked trivial to me, but even employing Seq.pairwise, IEnumerator<_>, sequence comprehensions and yield statements, the solution eludes me. I am sure that this is because I still lack experience with combining F#-idioms, or possibly because there are some language-constructs that I have not yet been exposed to.

// 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)))

推荐答案

我认为这符合您的要求

I think this does what you want

dataWithOccationalHoles 
|> Seq.pairwise
|> Seq.map(fun ((time1,elem1),(time2,elem2)) -> if time2-time1 = timeBetweenContiguousValues then 0, ((time1,elem1),(time2,elem2)) else 1, ((time1,elem1),(time2,elem2)) )
|> Seq.scan(fun (indexres,(t1,e1),(t2,e2)) (index,((time1,elem1),(time2,elem2))) ->  (index+indexres,(time1,elem1),(time2,elem2))  ) (0,(baseTime,-1.0),(baseTime,-1.0))
|> Seq.map( fun (index,(time1,elem1),(time2,elem2)) -> index,(time2,elem2) )
|> Seq.filter( fun (_,(_,elem)) -> elem <> -1.0)
|> PSeq.groupBy(fst)
|> Seq.map(snd>>Seq.map(snd))

感谢您提出这个很酷的问题

Thanks for asking this cool question

这篇关于F#:如何将一个序列拆分为一系列序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆