是否有一个库函数来执行类似set_elem
的声明?
set_elem (l : int list) (i : int) (x : int) : int list
例如:
(set_elem [1; 2; 3; 4] 1 90)
将返回:
[1; 90; 3; 4]
答案 0 :(得分:2)
没有,这很可能是因为直接索引对于不可变的链表来说是一个非常糟糕的用例,而这种便利功能无法正确反映成本。如果您发现自己经常这样做,则应考虑改用数组。
也就是说,我能想到的最简单的方法是仅在索引正确的情况下才使用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
答案 1 :(得分:1)
或者,如果您想使用可变数据结构,则Array
模块可以做到这一点。
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|] *)
答案 2 :(得分:0)
不,标准List库中没有库函数,但是向上编写代码并不难。
这是一个非尾递归实现。
(** [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}}。
否则,您将添加列表的旧元素,直到-1
达到0。
答案 3 :(得分:0)
当您只需要在O(n)
时间(其中{{1)运行时,其他解决方案将在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
。您可以根据需要更改此设置以引发异常。