我有两个记录列表,其中包含以下类型:
type AverageTempType = {Date: System.DateTime; Year: int64; Month: int64; AverageTemp: float}
type DailyTempType = {Date: System.DateTime; Year: int64; Month: int64; Day: int64; DailyTemp: float}
我想获得一个新的列表,它由DailyTempType“加入”和AverageTempType组成。最终,虽然每个日记录我想要匹配月份的每日温度 - 平均温度。
我想我可以按照下面的循环来做这个,然后将其按照合理的输出:
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"
我也尝试通过匹配来做到这一点,但我不能完全实现(我不确定如何在输入类型中正确定义列表然后迭代以获得结果。而且我不确定确定这种方法是否有意义):
let MatchPattern (x:DailyTempType) (y:AverageTempType) =
match (x,y) with
|(x,y) when (x.Year = y.Year && x.Month = y.Month) ->
printfn "match"
|(_,_) -> printfn "nomatch"
我已经研究过Deedle,我认为可以相对容易地做到这一点,但我很想知道如何做到这一点。
答案 0 :(得分:2)
您可以做的是创建月平均数据的地图。您可以将地图视为只读字典:
let averageDataMap =
averageData
|> Seq.map (fun x -> ((x.Year, x.Month), x))
|> Map.ofSeq
这个特定的地图是Map<(int64 * int64), AverageTempType>
,用更简洁的词来说,意味着地图中的键是年和月的元组,与每个键相关的值是AverageTempType
记录。
这使您可以根据每日数据找到所有匹配的月份数据:
let matches =
dailyData
|> Seq.map (fun x -> (x, averageDataMap |> Map.tryFind (x.Year, x.Month)))
此处,匹配项的数据类型为seq<DailyTempType * AverageTempType option>
。同样,在更简洁的单词中,这是一系列元组,其中每个元组的第一个元素是原始的每日观察,第二个元素是相应的月平均值,如果找到匹配,或None
如果没有找到匹配的月平均值。
如果要像在OP中那样打印值,可以执行以下操作:
matches
|> Seq.map snd
|> Seq.map (function | Some _ -> "Match" | None -> "No match")
|> Seq.iter (printfn "%s")
此表达式以matches
开头;然后拉出每个元组的第二个元素;然后再次将Some
值映射到字符串&#34;匹配&#34;,并将None
值映射到字符串&#34;不匹配&#34 ;;最后打印每个字符串。
答案 1 :(得分:0)
我会将第一个AverageTempType seq转换为Map(降低连接成本):
let toMap (avg:AverageTempType seq) = avg |> Seq.groupBy(fun a -> a.Year + a.Month) |> Map.ofSeq
然后你可以加入并返回一个选项,所以消费代码可以做你想做的任何事情(打印,存储,错误等):
let join (avg:AverageTempType seq) (dly:DailyTempType seq) =
let avgMap = toMap avg
dly |> Seq.map (fun d -> d.Year, d.Month, d.Day, d.DailyTemp, Map.tryFind (d.Year + d.Month) avgMap);;