2016-11-30 53 views
2

请考虑此数据集,由男人和女人组成的,而我根据几个变量在第二时刻过滤:添加计算关键收集

type ls = JsonProvider<"..."> 
let dt = ls.GetSamples() 

let dt2 = 
dt |> Seq.filter (fun c -> c.Sex = "male" && c.Height > Some 150) 

dt2 

[{"sex":"male","height":180,"weight":85}, 
{"sex":"male","height":160" "weight":60}, 
{"sex":"male","height":180,"weight":85}] 

让我们假设,我想补充的第四个关键“体重指数”或“bmi”,其值大致由“体重”/“身高”给出。因此,我预计:

[{"sex":"male","height":180,"weight":85, "bmi":(180/85)}, 
{"sex":"male","height":160" "weight":60, "bmi":(160/60}, 
{"sex":"male","height":180,"weight":85, "bmi":(180/85)}] 

我认为map.Add可能有所帮助。

let dt3 = dt2.Add("bmi", (dt2.Height/dt2.Weight))  

不幸的是,它会返回一个错误:

error FS0039: The field, constructor or member 'Add' is not defined 

我肯定有我的代码进一步的错误,但没有这个功能,我不能真正寻找他们。至少,我是否正确地接近问题?

回答

3

创建JSON的修改版本很遗憾,F#数据类型提供程序并不特别容易。让我们难以接受的是,我们可以从源JSON中推断出这种类型,但我们无法“预测”人们想要添加的字段类型。

为此,您需要访问JSON值的基础表示并对其进行操作。例如:

type ls = JsonProvider<""" 
    [{"sex":"male","height":180,"weight":85}, 
    {"sex":"male","height":160,"weight":60}, 
    {"sex":"male","height":180,"weight":85}]"""> 

let dt = ls.GetSamples() 

let newJson = 
    dt 
    |> Array.map (fun recd -> 
     // To do the calculation, you can access the fields via inferred types 
     let bmi = float recd.Height/float recd.Weight 

     // But now we need to look at the underlying value, check that it is 
     // a record and extract the properties, which is an array of key-value pairs 
     match recd.JsonValue with 
     | JsonValue.Record props -> 
      // Append the new property to the existing properties & re-create record 
      Array.append [| "bmi", JsonValue.Float bmi |] props 
      |> JsonValue.Record 
     | _ -> failwith "Unexpected format") 

// Re-create a new JSON array and format it as JSON 
JsonValue.Array(newJson).ToString() 
+0

其实我真的很难过。无论如何,它完美的作品,谢谢。我正在仔细研究它。我只有一个问题。以前,我用'let dt2 = dt |> Seq.filter(fun c - > c.Sex =“male”&& c.Height> 150)'过滤了数据集。这使'dt2'成为一个序列,并且它不好。我如何将'dt2传递给'type ls = JsonProvider '以使其再次成为json?如果你更舒适,我可以聊天。 – Worice

+1

您可以使用'Array.filter'进行过滤 - 这会将数据保存在数组中。 (或者,您可以在管道末端使用'Array.ofSeq')。 –