【问题标题】:creating a list of path in f#在 f# 中创建路径列表
【发布时间】:2023-03-16 09:05:01
【问题描述】:

(这可能是经典,但我想知道如何最好地表达它)

我从左边开始,在某个日期。 对于某些资产,我可以计算从开始日期到某个未来日期的回报。 从那个未来的日期开始,我可以递归地在时间上进一步移动。

我想生成尽可能向右的所有路径,但在某个目标日期之前停止。

这是我的代码。 'a 是一种资产,并且 (DateTime*DateTime) 是我对所述底层证券有报价的 2 倍。

  member this.getPaths dtstart dtend : Set<('a*(DateTime*DateTime)) list>=
     let rec getPaths dtstart dtend (pastpath:List<'a*(DateTime*DateTime)>) : seq<('a*(DateTime*DateTime)) list>=
        let udls = this.getUnderlyingsQuotingAt dtstart
        let onestep = seq { for udl in udls do
                                let qt = this.QuoteNextAfterSrict udl dtstart 
                                if qt.IsNone || (qt.Value |> fst > dtend) then
                                   yield pastpath |> List.rev  
                                else
                                   let nextdate = qt.Value |> fst 
                                   yield! (getPaths nextdate dtend  ((udl, (dtstart, nextdate))::pastpath) )  } 
        onestep
     getPaths dtstart dtend  List.empty |> Set.ofSeq 

由于我使用了yield!,最后我会为每次失败收集一条新路径。 所以,最后我必须对我的序列进行重复数据删除。 我的问题是:有没有更好的方法来找到完整的路径,而无需重复数据删除?

我可以进行第二次传递或添加一个 List 参数,但是是否有一些“纯粹”的方法可以一次性做到这一点?

更新

我认为我在许多无用的内部循环中弄错了整个方法。 可能矢量化下一个可用的报价会很有用。我会在重构后更新代码。

更新 2

第一次重写是以下内容,将 yield |> List.rev 上移一级,允许减少不必要的探索。

  member this.getPaths dtstart dtend : Set<('a*(DateTime*DateTime)) list>=
     let count = ref  0

     printfn "computing path from %A to %A " dtstart dtend
     let rec getPaths dtstart dtend (pastpath:List<'a*(DateTime*DateTime)>)  : seq<('a*(DateTime*DateTime)) list>=
        let udls      = this.getUnderlyingsQuotingAt dtstart
        let udlquotes = udls |> Seq.map   (fun udl -> (udl , this.QuoteNextAfterSrict udl dtstart))
                                              |> Seq.filter (fun   (_, q) -> q.IsSome)
                                              |> Seq.map    (fun   (udl, q) -> (udl, q.Value))
                                              |> Seq.filter (fun   (_, q) -> fst q <= dtend  )

        let onestep = seq { if udlquotes.IsEmpty then
                                yield pastpath  |> List.rev  
                            else
                                for (udl, q) in udlquotes  do
                                      let nextdate =  (fst q)
                                      count := !count + 1
                                      if !count%1000 = 0 then printfn "!count  %A , path : %A " !count pastpath
                                      yield! (getPaths nextdate dtend  ((udl, (dtstart,  nextdate))::pastpath)   )
                       }
        onestep
     getPaths dtstart dtend  List.empty |> Set.ofSeq 

【问题讨论】:

  • 我意识到它没有回答您的问题,但您可能会做的一件事是使用类型别名来使您的代码更易于阅读。您至少在两个地方使用了 'a*(DateTimeDateTime)。这可能更容易阅读 type datespan = 'a*(DateTimeDateTime) 然后在您的集合和列表中使用 datespan。正如我所说,我意识到这并不能回答您的问题,但它会使您的代码更易于阅读。
  • 你是完全正确的。谢谢你的建议。我将添加一些关于代码的cmets。

标签: graph f# primitive


【解决方案1】:

我不太了解您的算法,但我认为总体结构看起来不错。 “重复数据删除”是什么意思?如果您指的是在递归处理结束时使用的 List.rev 调用,那么这是很常见的模式(我认为没有更好的方法来做到这一点)。

关于 F# 编码风格,在分析 qt 值时无法轻松使用模式匹配,这有点令人失望(因为无法使用内置模式对条件进行编码)。但是,您可以定义一个在输入大于参数时匹配的辅助参数化活动模式:

let inline (|MoreThan|_|) limit input = 
  if input > limit then Some input else None

使用该模式,您可以使 seq 的正文更具可读性:

let rec getPaths dtstart dtend pastpath = seq {
  let udls = this.getUnderlyingsQuotingAt dtstart 
  for udl in udls do 
    match this.QuoteNextAfterSrict udl dtstart with
    | None 
    | Some (MoreThan dtend _, _) ->
        yield pastpath |> List.rev   
    | Some (nextdate, _) ->
        let newpath = (udl, (dtstart, nextdate))::pastpath
        yield! getPaths nextdate dtend newpath }  

【讨论】:

  • 对于重复,假设我有 10 个底层证券,并且 (qt.Value |> fst > dtend) 中的所有测试都会导致终止。我将有一个包含 10 个空序列的序列。我会研究你的建议,这看起来更惯用。谢谢。
  • @nicolas 啊,我开始明白了——所以,基本上,如果QuoteNextAfterStrict udl dtstartudls 中的任何udl 返回匹配第一个模式(在我的版本中)的值,那么你想产生一次pastpath |&gt; List.rev,否则你想产生零次?
  • @nicolas 如果是这种情况,我可能会使用List.mapudls 中的所有值运行QuoteNextAfterStrict,然后测试所有值是否与第一个模式匹配 - 如果是,您可以返回pastpath |&gt; List.rev。然后你可以遍历那些匹配第二个模式并递归地产生。您可以使用List.partition 将它们分成两种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2019-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多