如何从元组列表创建记录

How to create record from tuple list

如何从下面的元组列表((字符串*字符串)列表)创建记录(t)?

From: [("field1", "foo"); ("field2", "bar"); ("field3", "baz")]

To: { field1: "foo"; field2: "bar"; field3: "baz" }

我可以使用可变字段来实现,如下所示,但还有其他方法吗?

type t = {
    mutable key1: string;
    mutable key2: string;
    mutable key3: string;
}

let set (key, value) item =
    match key with
    | "key1" -> item.key1 <- value; item
    | "key2" -> item.key2 <- value; item
    | "key3" -> item.key3 <- value; item
    | _ -> item

let to_rec list =
    let rec aux acc = function
        | [] -> acc
        | h :: t -> aux (set h acc) t
    in
    aux { key1 = ""; key2 = ""; key3 = "" } list

一个列表可以包含任意数量的元素或none。记录类型恰好包含一定数量的字段。我略有根据的猜测是 Hashtbl.

会更好

我们可以很容易地编写一个函数,该函数将获取一个列表并根据其内容创建一个散列 table。

let convert_to_hash lst =
  let rec aux h = function
  | [] -> h
  | (k, v)::xs -> (Hashtbl.add h k v; aux h xs)
  in
  aux (Hashtbl.create 20) lst

如果我们在您的示例数据上调用它:

let h = convert_to_hash [("field1", "foo"); ("field2", "bar"); ("field3", "baz")]

然后遍历那个散列table,我们可以看到结果:

utop # Hashtbl.iter (Printf.printf "%s => %s\n") h;;
field1 => foo
field3 => baz
field2 => bar
- : unit = ()

您可能还想用 Map 实现这种功能,但考虑到您的所有记录字段都标记为 mutable,Hashtbl 在这种情况下可能更合适.

不需要使用可变字段,您可以使用with来更新记录的字段,例如

let of_list = List.fold_left (fun r (k,v) ->
    match k with
    | "field1" -> {r with field1=v}
    | "field2" -> {r with field2=v}
    | "field3" -> {r with field2=v}
    | s -> invalid_arg ("an unexpected field " ^ s))
   {field1=""; field2=""; field3=""}

当您有预定义的输入语法时,即您确定列表中的字段将按特定顺序排列(或者您只是对它们进行排序),您可以直接在列表的结构上进行模式匹配,例如,

let of_list = function
  | ["field1", field1;
     "field2", field2;
     "field3", field3] -> {field1; field2; field3}
  | _ -> invalid_arg "expected the predefined structure"

最后,如果性能不是很重要,可以使用List.assoc查询字段,例如

let of_list elts = {
  field1 = List.assoc "field1" elts;
  field2 = List.assoc "field2" elts;
  field3 = List.assoc "field3" elts;
}