Array: a `for_all` taking index into account

I want to check a property for all items of an array and that property depends on the index of the item. Similar to Array.iteri compared with Array.iter, I can define a function

let for_alli p a =
  for_all2 p (Array.init (Array.length a) Fun.id) a

but then looking at the stdlib implementation of for_all, I see that I can simply tweak it to obtain

let for_alli' p a =
  let n = length a in
  let rec loop i =
    if i = n then true
    else if p i (unsafe_get a i) then loop (succ i)
    else false in
  loop 0

(I simply added one i after the p.)

It’s probably faster since compared to the version using for_all2, I have half as many get’s, I save two length computations, and I avoid one array initialization.

However, there is an unsafe_get and the documentation says “The following is for system use only. Do not call directly.”

What should I do ? Use for_alli, or for_alli', or for_alli' with a.(i) instead of unsafe_get to get the index (which I imagine is slower) ?

If you’re not averse to using to using Core from Jane Street, then you can use its Array.for_alli, which itself uses unsafe_get.

for_alli' with a.(i) should be your first try. You can always switch to unsafe_get later, as an optimization. Note that for_alli is particularly inefficient, allocating a potentially large array just to get ahold of the indices. Another alternative:

let i = ref (-1) in
Array.for_all (fun x -> incr i; p !i x) a

Cheers,
Nicolas

1 Like