加入两个记录列表并计算结果

时间:2014-10-01 06:00:27

标签: 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}

我想获得一个新的列表,它由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,我认为可以相对容易地做到这一点,但我很想知道如何做到这一点。

2 个答案:

答案 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);;