我像这样编写map_tail
的尾递归版本:
let map_tail f l =
let rec map acc = function
| [] -> List.rev acc
| hd::tl -> map (f hd :: acc) tl
in
map [] l
然后是基于map_by_array
的数组:
let map_by_array f l =
Array.of_list l |> Array.map f |> Array.to_list
以下是基准代码
let ran_list n =
Random.self_init();
let rec generate acc i =
if i = n then acc
else generate (Random.int 5::acc) (i+1)
in
generate [] 0
let _ =
let l = ran_list 10000000 in
let f x = x+1 in
let t1 = Sys.time() in
let l1 = map_tail f l in
let t2 = Sys.time() in
let l2 = map_by_array f l in
let t3 = Sys.time() in
Printf.printf "map_tail: %f sec\nmap_by_array: %f sec\n" (t3-.t2) (t2-.t1)
我发现基于数组的地图速度更快,这让我感到很惊讶。
在map_tail
中,它会遍历列表twice
而map_by_array
遍历列表three times
,为什么它仍然更快?
答案 0 :(得分:3)
这可能取决于列表的大小。
在大小为N的长列表中,map_tail
将执行 2 * N 分配(地图中为N,然后List.rev
为N),而map_by_array
}将执行 N + 2 分配(Array.of_list
为1,Array.map
为1,Array.to_list
为N,实际上可以优化为仅一个分配也是)。
由于分配可能是此代码中最昂贵的操作,因此这种差异应该可以解释性能的差异。