(Это, вероятно, классический, но мне интересно, как лучше всего это выразить)создания списка пути в F #
я начинаю на левой стороне, в какой-то момент. Для некоторых активов я могу вычислить доходность от начальной даты до некоторой будущей даты. С этой будущей даты я могу двигаться дальше во времени рекурсивно.
Я хотел бы сгенерировать весь путь, который идет как можно дальше вправо, но это останавливается до какой-либо намеченной даты.
Вот мой код. «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
Первое переписывание заключается в следующем, которые перемещаются выходом |> 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 * (DateTime * DateTime) как минимум в двух местах. Это может быть немного легче читать даты __type <'a> = 'a * (DateTime * DateTime) __, а затем использовать даты в вашем наборе и списке. Как я уже сказал, я понимаю, что это не отвечает на ваш вопрос, но это сделает ваш код немного легче читать. –
вы совершенно правы. спасибо за ваше предложение. Я добавлю некоторые комментарии к этому коду. – nicolas