how to get a sub list from a list in ocaml

主宰稳场 提交于 2020-01-03 07:28:06

问题


I'm looking at the List documentation. It seems the library does not provide a sublist function.

I'm trying to get list of elements from i to j. Now I have to write it as:

let rec sublist list i j =
  if i > j then
    []
  else
    (List.nth list i) :: (sublist list (i+1) j)

which is quite concise but I'm questioning the efficiency of List.nth, because if it's O(n), I would rather have to write it in a less concise way.

I'm wondering why didn't they provide List.sublist func, if List.nth is not O(1), because it's such a quite common operation..


回答1:


let rec sublist b e l = 
  match l with
    [] -> failwith "sublist"
  | h :: t -> 
     let tail = if e=0 then [] else sublist (b-1) (e-1) t in
     if b>0 then tail else h :: tail
;;

sublist 3 5 [1;2;3;4;5;6;7;8;9] ;;
- : int list = [4; 5; 6]

The above is more or less a deforested version of newacct's solution. newacct's solution allocates an intermediate list (drop i list), which is possible for the compiler to optimize away in Haskell but much harder in ML. Therefore his version is perfectly fine for a Haskell function and marginally sub-optimal for an ML one. The difference between the two is only a constant factor: both are O(e). zrr's version is O(length(l)) since List.filteri doesn't know that f only returns false after a while, it calls it for all elements in l.

I'm not very happy to let b go negative but the version where it doesn't is more complicated.

One reference among quite a few for deforestation if you're interested: http://homepages.inf.ed.ac.uk/wadler/topics/deforestation.html




回答2:


Try writing the take (first n items) and drop (everything but the first n items) functions (like in Haskell) first. Then sublist i j lst is just take (j-i) (drop i lst)




回答3:


This is a bit harder than it should be with OCaml's standard library --- the standard library is a bit sparse. If you use one of the extended standard libraries, it gets easier. With Core, for example, you could write:

let sublist list low high =
   List.filteri l ~f:(fun i _ -> i >= low && pos < high)

I imagine something similar is possible with extlib/batteries.




回答4:


While the answer provided by Pascal implements a nice candidate for List.sublist the right answer is that you should probably better use an array of a list. The Array modules implements the Array.sub function that you might use.

While in many imperatives languages such as C++ or Perl there is essentially no difference between lists and arrays, this is not the same in OCaml where:

  • Lists are better suited for recursive treatments and sequential access, i.e. is usually a better candidate as an array as argument to a recursive function, and you usually want to take a look at all the elements of the list.

  • Arrays are better suited for random access, structure alteration (such as sorting), or for numerical computations.



来源:https://stackoverflow.com/questions/2710233/how-to-get-a-sub-list-from-a-list-in-ocaml

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!