List 用于设置列表第n个元素的库函数

List 用于设置列表第n个元素的库函数,list,ocaml,List,Ocaml,是否有一个库函数来执行这样的set\u elem声明 set_elem (l : int list) (i : int) (x : int) : int list 例如: (set_elem [1; 2; 3; 4] 1 90) 将返回: [1; 90; 3; 4] 不,标准库中没有库函数,但是编写一个库函数并不难 这是一个非尾部递归实现 (** [insert n el lst] inserts element [el] in the [n]th position in the

是否有一个库函数来执行这样的
set\u elem
声明

set_elem (l : int list) (i : int) (x : int) : int list
例如:

(set_elem [1; 2; 3; 4] 1 90)
将返回:

[1; 90; 3; 4]

不,标准库中没有库函数,但是编写一个库函数并不难

这是一个非尾部递归实现

(** [insert n el lst] inserts element [el] in the [n]th position in the 
    list [lst].
    Raises: [Failure] if index is out of bounds *)
let rec insert n el lst =
  match n,lst with 
  | i, _ when i >= List.length lst -> failwith "Index out of Bounds"
  | _, [] -> []
  | 0, _::t -> el::(insert (-1) el t)
  | i, h::t -> h::(insert (i-1) el t)
其思想是将模式匹配与
n
lst
一起进行

如果点击空列表,则返回初始值(如果需要尾部递归解决方案,则返回累加器)

如果
n
点击0,则将元素附加到列表中,并继续浏览列表的其余部分以保留其他元素(但请确保不再点击0,这就是我使用
-1
的原因)


否则,您将添加列表中的旧元素,直到
n
达到0。

或者,如果您希望使用可变数据结构,则
数组
模块可以完全做到这一点

let a = [|1; 2; 3; 4|];;
(* val a : int array = [|1; 2; 3; 4|] *)

Array.set a 1 90;;
(* - : unit = () *)

a;;
(* - : int array = [|1; 90; 3; 4|] *)

没有,这可能是因为直接索引对于不可变链表来说是一个非常糟糕的用例,其成本并没有通过这些方便的函数得到适当的反映。如果你发现自己经常这样做,你应该考虑使用数组。 也就是说,我能想到的最简单的方法是使用
List.mapi
仅在索引正确时返回新元素,否则返回现有元素:

List.mapi (fun i el -> if i = 1 then x else el) l
或作为具有所需签名的函数:

let set_elem (l : int list) (i : int) (x : int) : int list =
  List.mapi (fun i' el -> if i = i' then x else el) l

其他解决方案在
O(n)
时间内运行(其中
n
是列表的长度),而您实际上只需要解决方案在
O(i)
时间内运行(其中
i
是索引)

下面是一个高效的尾部递归函数:

let set l ~i ~data =
  let rec helper ~prev_rev ~curr ~i =
    match curr, i with
    | []        , _ -> List.rev prev_rev
    | _  :: curr, 0 -> List.rev_append prev_rev (data :: curr)
    | hd :: curr, _ -> helper ~prev_rev:(hd :: prev_rev) ~curr ~i:(i - 1)
  in
  if i < 0 || i >= List.length l
  then l
  else helper ~prev_rev:[] ~curr:l ~i
设置l~i~数据=
让rec helper~prev_rev~curr~i=
搭配咖喱,我喜欢
|[],->List.rev prev\u rev
|当前,0->List.rev\u append prev\u rev(数据:当前)
|hd::curr,->helper~prev\u rev:(hd::prev\u rev)~curr~i:(i-1)
在里面
如果i<0 | | i>=List.length l
然后我
else helper~prev_rev:[]~curr:l~i
如果传入无效索引,此函数不会更改
l
。如果愿意,可以更改此项以引发异常