F# 合并两个记录列表并计算结果

F# 合并两个记录列表并计算结果,f#,F#,我有以下两种类型的记录列表: type AverageTempType = {Date: System.DateTime; Year: int64; Month: int64; AverageTemp: float} type DailyTempType = {Date: System.DateTime; Year: int64; Month: int64; Day: int64; DailyTemp: float} 我想得到一个新的列表,它由DailyTestType和AverageTest

我有以下两种类型的记录列表:

type AverageTempType = {Date: System.DateTime; Year: int64; Month: int64; AverageTemp: float}
type DailyTempType = {Date: System.DateTime; Year: int64; Month: int64; Day: int64; DailyTemp: float}
我想得到一个新的列表,它由DailyTestType和AverageTestType组成。不过,对于每一条每日记录,我希望得到匹配月份的每日温度-平均温度

我想我可以使用如下所示的循环,并将其按摩成合理的输出:

let MatchLoop = 
    for i in DailyData do
        for j in AverageData do
                if (i.Year = j.Year && i.Month = j.Month) 
                then printfn "%A %A %A %A %A" i.Year i.Month i.Day i.DailyTemp j.Average
                else printfn "NOMATCH" 
我也尝试过通过匹配来实现这一点,但我不能完全做到(我不确定如何在输入类型中正确定义列表,然后迭代以获得结果。我也不确定这种方法是否有意义):


我已经研究过Deedle,我认为它可以相对容易地做到这一点,但我渴望了解如何在较低的级别上做到这一点。

我会将first AverageTestType seq转换为Map(降低连接成本):

然后,您可以加入并返回一个选项,以便使用代码可以执行任何您想要的操作(打印、存储、错误等):


您可以做的是创建月平均数据的地图。您可以将地图视为只读词典:

let averageDataMap =
    averageData
    |> Seq.map (fun x -> ((x.Year, x.Month), x))
    |> Map.ofSeq
这个特定的映射是一个
映射
,用更简单的话来说,这意味着映射中的键是年和月的元组,与每个键相关联的值是一个
平均类型
记录

这使您能够根据每日数据查找所有匹配的月份数据:

let matches = 
    dailyData
    |> Seq.map (fun x -> (x, averageDataMap |> Map.tryFind (x.Year, x.Month)))
这里,matches的数据类型为
seq
。同样,简单地说,这是一个元组序列,其中每个元组的第一个元素是原始的每日观察值,第二个元素是相应的月平均值(如果找到匹配项),或者
None
如果没有找到匹配的月平均值

如果要打印OP中的值,可以执行以下操作:

matches
|> Seq.map snd
|> Seq.map (function | Some _ -> "Match" | None -> "No match")
|> Seq.iter (printfn "%s")

此表达式以匹配的
开头;然后取出每个元组的第二个元素;然后再次将
Some
值映射到字符串“Match”,将
None
值映射到字符串“No Match”;最后打印每个字符串。

列表是否已排序?如果你想在较低的级别上做一些事情,这一点很重要。我可以让他们按照我想匹配的键进行排序。@Fusi123你总是可以使用,或者只是研究它是如何实现的,以及它如何提供与
左外连接等效的功能。
…)谢谢,马克,这很好用。你能解释一下(或者可能是一个参考资料)如何正确处理期权类型吗?如果我使用Map.find,我可以使用
matches |>Seq.Map(fun(x,y)->x.DailyTemp,x.DailyTemp-y.AvgTemp)|>printfn“%A”
选项类型记录在这里:另一个值得一读的好方法是:谢谢马克,我看了这些例子。尽管如此,我仍然有点挣扎,因为所有的例子似乎都是琐碎的案例。我看不到有一系列选项的情况,我也无法更改您的示例,因为我无法“访问”原始元组。我可能会发布另一个问题。
let averageDataMap =
    averageData
    |> Seq.map (fun x -> ((x.Year, x.Month), x))
    |> Map.ofSeq
let matches = 
    dailyData
    |> Seq.map (fun x -> (x, averageDataMap |> Map.tryFind (x.Year, x.Month)))
matches
|> Seq.map snd
|> Seq.map (function | Some _ -> "Match" | None -> "No match")
|> Seq.iter (printfn "%s")