Search code examples
rubynarray

Selecting values below a threshold and anchored at the left or right using Ruby NArray


Using NArray, is there some nifty way to create masks of arrays with values below e.g. 5, but only for runs of values anchored a the left or right side, E.g. this 1-D array:

[3, 4, 5, 7, 1, 7, 8]

would result in:

[1, 1, 0, 0, 0, 0, 0]

And this 2-D array:

[[2, 4, 5, 7, 1, 2, 3], 
 [3, 4, 5, 7, 1, 7, 8],
 [8, 1, 1, 7, 1, 7, 1]]

would result in:

[[1, 1, 0, 0, 1, 1, 1], 
 [1, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 1]]

Solution

  • require "narray"
    
    def anchor_mask(mask)
      idx = (mask.not).where
      y = idx/mask.shape[0]
      u = (y[0..-2].ne y[1..-1]).where
      t = [0] + (u+1).to_a + [idx.size]
      s = (0..u.size).map{|i| idx[t[i]]..idx[t[i+1]-1]}
      mask[s] = 0
      return mask
    end
    
    a = NArray[3, 4, 5, 7, 1, 7, 8]
    
    p anchor_mask a.lt(5)
    #=> NArray.byte(7):
    #   [ 1, 1, 0, 0, 0, 0, 0 ]
    
    a = NArray[[2, 4, 5, 7, 1, 2, 3],
               [3, 4, 5, 7, 1, 7, 8],
               [8, 1, 1, 7, 1, 7, 1]]
    
    p anchor_mask a.lt(5)
    #=> NArray.byte(7,3):
    #   [ [ 1, 1, 0, 0, 1, 1, 1 ],
    #     [ 1, 1, 0, 0, 0, 0, 0 ],
    #     [ 0, 0, 0, 0, 0, 0, 1 ] ]