How to filter out Nones from array(option(a'))?


#1

I tried:

let arrayOfValues = arrayOfOptions |> Js.Array.filter(a => 
        switch(a) {
        | Some(_) => true
        | None => false
        });

but arrayOfValues still contains optionals.


#2

Belt.Array.keepMap applies a function to each element of an array and keeps only the values for which the function returns Some(value); since your array already consists of optionals, a function that returns the item unchanged will do exactly what you need.

let arr = [|Some(3), None, Some(5), None, Some(7)|];

let filtered = Belt.Array.keepMap(arr, fun (x) => x);

Js.log(filtered); /* produces [|3, 5, 7|] */

#3

That’s exactly what I was looking for. In my searches I found filter_map but it looks like it’s for Lists and only supported in OCaml.


#4

@jdeisenberg I have a follow about question about Belt.Array.keepMap, is there a way to use it with |>? I guess I could define a function which reverses the params, but it seems weird to have to do that. Is there a reason why Belt.Array functions accept the array as the first param?


#5

There’s a special notation |. to pipe to the first argument:

/* dummy function that produces an array of optional ints */
let makeArr = () : array(option(int)) => {
  [|Some(3), None, Some(5), None, Some(7)|];
};

let filtered = makeArr() |. Belt.Array.keepMap(fun (x) => x);

You can also use |> with _ to replace any specific argument you want, but somewhere I read it is not as performant as |.

let filtered = makeArr() |> Belt.Array.keepMap(_, fun (x) => x);

#6

Awesome! Thanks. I’m feeling much better now. :slight_smile:


#7

Belt is probably the way to go - but here’s another way -

/**
 * Given an array or a list of options, return only the
 * items that are Some(item)
 **/
let arr_only_some = (arr) => Array.fold_right(
    (x, result) =>
      switch x {
      | Some(i) => Array.append([|i|], result)
      | None => result
      },
  	arr,
    [||]
  );