How would you iterate over array and return index where value is null?

I am trying to go through the array (fixed 10 items array in this case) and would like to return the INDEX to where I would like to store a value of the first occurence where the value is NULL. How would you do this in Motoko ?

Currently, I am trying to do this using the Iter library but the compiler does not like this

private let canisters : [var ?CanisterState<Bucket, Nat>] = Array.init(0, null);

let canistersIter = Iter.range(0, canisters.size() - 1);
    let index = for(i in canistersIter) {
      switch (canisters[i]) {
        case null {
          break i;
        };
        case (?canister) continue // what should I return as value after continue as it fails if there is none?;
      };
    };

The docs are pretty confusing to me regarding this, can’t figure out how to do this. Any help appreciated :slight_smile:

I have “solved” this issue by using following code:

    var index: Nat = 0;
    let canistersIter = Iter.range(0, canisters.size() - 1);

    for (canisterState in canistersIter) {

      switch(canisters[canisterState]) {
        case null { index := canisterState };
        case (?cs) {};
      }
    };

I am not sure if this is the (best) way of doing it or not, would like opinion of more experienced ICP devs on this whether or not it’s a good way to do so and/or if there is an easier way (maybe Iter does not need to be used at all)?

I think your solution is okayish, except for two remarks:

  • It will not be able to distinguish finding null at the first slot from not having found it anywhere. I think you actually want type ?Nat.
  • You can simplify the iterator by using canister.keys().

Together, that would be:

  var index : ?Nat = null;
  for (i in canisters.keys()) {
    switch(canisters[i]) {
      case null { index := ?i };
      case (?cs) {};
    }
  };

Alternatively, if you’re keen on avoiding the mutable variable, you could do something like this, which is closer to your first attempt:

    let index : ?Nat =
      label l {
        for (i in canisters.keys()) {
          switch(canisters[i]) {
            case null { break l(?i) };
            case (?cs) {};
          }
        };
        null
      }
    };

But I’m not sure that’s more readable.

3 Likes

Thank you very much for the examples! :slight_smile: I think that I will probably switch to using the label example since in my code i just want to find the first element in the array where value is null (so basically first element that was not yet set) and I believe the break l(?i) is the way to do it, without the need to iterate over the whole array (will be faster)

Very cool, I didn’t know that labeled expressions were a thing until reading this.

2 Likes

You could also wrap the switch as a local function and then even use something like map instead of imperatively iterating.