将计算出的键添加到集合中

Add calculated key to collection

请考虑这个由男人和女人组成的数据集,我根据几个变量在第二时刻过滤:

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}]

假设我想添加第四个键 "body mass index" 或 "bmi",其值大致由 "weight"/"height" 给出。因此我预计:

[{"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))       

不幸的是,它 returns 一个错误:

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

我确定我的代码中还有更多错误,但如果没有这个函数,我实际上无法查找它们。至少我是否正确地解决了这个问题?

创建 JSON 的修改版本令人遗憾的是,F# 数据类型提供程序并没有使它变得特别容易。困难在于我们可以从源 JSON 推断类型,但我们无法 "predict" 人们可能想要添加什么样的字段。

为此,您需要访问 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()