# array manipulation without for loops

Alex Martelli aleax at mac.com
Sun Jun 25 23:18:25 CEST 2006

```Sheldon <shejo284 at gmail.com> wrote:

> The following script (using your function) raised no exception so it
> worked! Elegant Alex, thanx.
>
> res = equalize_arrays(msgtmp,ppstmp,255) # class
>             (ppstmp,msgtmp) = res.equalize() # class method
>             for i in range(int(main.xsize)):
>                 for j in range(int(main.ysize)):
>                     if msgtmp[i,j] == 255 and ppstmp[i,j] != 255:
>                         raise "equalize error!"
>                     if ppstmp[i,j] == 255 and msgtmp[i,j] != 255:
>                         raise "equalize error!"
> I read up on the putmask function and I don't understand this part:
>
> >>> print x
> [10 1 30 3 50]
> >>> print x
> [-1 1 -1 3 -1]
>
> Can you explain why the -2 didn't factor in?

Because it always happens in places where the mask is 0, of course --
the third argument gets conceptually "repeated" to get the length of the
mask, giving [-1, -2, -1, -2, -1] -- and the "-2" always occur where the
mask is 0, so they don't matter.  Exactly as I would expect from:

If v is shorter than mask it will be repeated as necessary.
In particular v can be a scalar or length 1 array.

and I just can't see where you might have formed any different
expectations from this documentation.  Use a different mask, say
[1,0,0,1,1] -- and the -2 in 4th place will be set into x, just like the
-1 ocurrences at the start and end.

Similarly, say:

>>> Numeric.compress([1,0,1,0,1], [-1, -2]*3)
array([-1, -1, -1])

even though here we have to explicitly use the "*3" part for repetition
since compress, differently from putmask, doesn't implicitly repeat the
last argument, the idea is similar: pick only elements corresponding to
a true value in the mask argument.

If what you want is to put -1 where the first 1 in the mask occurs, -2
where the 2nd 1 in the mask occurs, and so forth, you need some
auxiliary manipulation of the indices to prepare the proper "values"
array, for example:

import Numeric

class SequenceRepeater(object):
def __init__(self, seq, thelen):
self.seq = seq
self.len = thelen
def __len__(self):
return self.len
def __getitem__(self, i):
if i<0: i += self.len
return self.seq[i % len(self.seq)]

if __name__ == '__main__':
x = Numeric.zeros(5)
strangeput(x, [1, 0, 1, 0, 1], [-1, -2])
print x

brain:~/pynut alex\$ python pr.py
[-1  0 -2  0 -1]

There may be simpler and faster approaches for this, of course, but I
had this SequenceRepeater auxiliary class in my "mixed bag of useful
stuff" so I just copied-and-pasted a solution based on it!-)

Alex

```