问题
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