F#:如何将一个序列分成一个序列 [英] F#: How do i split up a sequence into a sequence of sequences
问题描述
背景:
我有一系列连续的,带时间戳的数据.数据序列在其中数据不连续的地方有间隙.我想创建一种将序列拆分为序列序列的方法,以使每个子序列包含连续数据(将输入序列拆分为空白).
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模式(参见)
- 对功能惯用方法的加分(因为我想精通函数式编程),但这不是必需的.
- 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屋!