5

For example in Ruby you could do something like:

list = ["foo", "bar", "baz", "qux", "quux", "corge"]
result = list[2..4]

And result would contain ["baz", "qux", "quux"].

How would you do this in OCaml/ReasonML?

Erik
  • 4,268
  • 5
  • 33
  • 49
  • use pattern matching or a library with give and take https://stackoverflow.com/questions/2710233/how-to-get-a-sub-list-from-a-list-in-ocaml – Serge Oct 26 '18 at 19:33
  • for reason use List.hd and List.tk https://reasonml.github.io/api/List.html , Array module has sub – Serge Oct 26 '18 at 19:37

5 Answers5

5

There is no in built function for slicing list, but can be done easily. Since we have a start point and an end point, we can break down the problem in two parts. First part is to drop a few elements till we reach the starting point and second part is to take few elements from the start point till the end point.

let rec drop = (n, list) =>
  switch (list) {
  | [] => []
  | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
  };

let rec take = (n, list) =>
  switch (list) {
  | [] => []
  | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
  };

now that we have these two functions, we can combine them to drop initial elements from till start point drop(i, list) and then pass this new list to take elements from start point to end point

take(k - i + 1, drop(i, list));

in total

let slice = (list, i, k) => {

  let rec drop = (n, list) =>
    switch (list) {
    | [] => []
    | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
    };

  let rec take = (n, list) =>
    switch (list) {
    | [] => []
    | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
    };

  take(k - i + 1, drop(i, list));
};

A better approach would be to provide starting point and then range rather than end point because here we don't constraint that end point should be bigger than starting point

let slice = (list, start, range) => {

  let rec drop = (n, list) =>
    switch (list) {
    | [] => []
    | [_, ...xs] as z => n == 0 ? z : drop(n - 1, xs)
    };

  let rec take = (n, list) =>
    switch (list) {
    | [] => []
    | [x, ...xs] => n == 0 ? [] : [x, ...take(n - 1, xs)]
    };

  take(range, drop(start, list));
};
shrynx
  • 66
  • 2
2

If you have access to bucklescript's Belt libraries, you could do something like:

open Belt;

let myList = ["first", "second", "third", "fourth", "fifth", "sixth"];

/* To get 2..4 */
myList
  ->List.drop(2)
  ->Option.getWithDefault([])
  ->List.take(3)
  ->Option.getWithDefault([])
  ->Js.log;

/* Gives you the list ["third", "fourth", "fifth"] */
csb
  • 674
  • 5
  • 13
1

There is no special language notation for OCaml slicing. You can write your function, say using the pattern matching, or combine head with take functions (those are available in standard libraries). For Reason combine List.hd and List.tk https://reasonml.github.io/api/List.html , also Array module has a sublist Array.sub. The OCaml was discussed here how to get a sub list from a list in ocaml

Serge
  • 3,387
  • 3
  • 16
  • 34
1

If you have access to BuckleScript, you can use:

let list = ["foo", "bar", "baz", "qux", "quux", "corge"];

let sliced = Js.Array.slice(~start=2, ~end_=4, list);

See more in the BuckleScript docs

Eric
  • 740
  • 6
  • 10
1

Use

List.filteri (fun i _ -> i >= start && i <= end)
glennsl
  • 28,186
  • 12
  • 57
  • 75
Anarchos
  • 11
  • 1
  • 3
    Welcome to Stack Overflow! While this code may solve the question, [including an explanation](//meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Yunnosch Dec 19 '20 at 23:17