我想在未来至少X天/分钟/秒加入记录到下一条记录。我需要使用具有几十万个记录的数组来完成此操作。我对序列/列表/数组持开放态度,但我相信数组可能是最快的。
我可以使用init
在Deedle中快速完成此操作,但我可以更轻松地使用标准数组/序列/列表进行转换。
以下示例适用于1000条记录,但在100k时非常慢。评论here建议使用二分搜索,但我不知道如何在搜索基于不等式的情况下执行此操作。
last
答案 0 :(得分:4)
问题在于这个表达式:
let r2 =
rs
|> Array.filter (fun x -> x.Date > futureDay)
|> Array.tryHead
这会过滤整个数组,并在您真正想要第一个匹配项时,使用 all 匹配项创建一个新数组。这种情况发生在每r
。试试这个:
let r2 = rs |> Array.tryFind (fun x -> x.Date > futureDay)
N.b。如果你处理的是序列而不是数组,那么你的逻辑会很好,因为过滤器会被懒惰地评估,但当然序列通常比数组慢。要记住的是,Seq
模块是懒惰的(有一些例外),而使用Array
和List
(以及Set
和{{1}时如果模块,链/管道中的每一步都会急切地分配一个新的Map
/ list
,因此在处理大型集合时会非常昂贵。
如果排序array
不会影响您的逻辑或预期输出,则可以使用Array.FindIndex
开始在rs
索引处进行搜索,从而进一步改进而不是每次从数组的开头:
r
即使采用Array.sortInPlace rs
rs
|> Seq.mapi (fun i r ->
let futureDay = r.Date.AddDays 4.0
let r2Index = Array.FindIndex (rs, i, (fun x -> x.Date > futureDay))
match r2Index with
| -1 -> None
| i' -> let x = rs.[i']
Some { Date1=r.Date; Value1=r.Value; Date2=x.Date; Value2=x.Value })
|> Seq.choose id
|> Array.ofSeq
方法,也应该提供显着改进,因为每次只需要扫描少量数组元素。
以下是我老化平板电脑的FSI时序,系统处于零负载状态:
Array.tryFind
(原始代码):00:00:08.783 Array.filter
:00:00:03.844 Array.tryFind
+ Array.sort
:00:00:00.027 Seq.mapi
:我没有打扰。Array.filter
:00:06:14.288 Array.tryFind
+ Array.sort
:00:00:00.305