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]
> >>> putmask(x, [1,0,1,0,1], [-1,-2])
> >>> 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:
>>> print Numeric.putmask.__doc__
putmask(a, mask, v) results in a = v for all places mask is true.
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)]
def strangeput(anarray, amask, somevalues):
repeater = SequenceRepeater(somevalues, len(amask))
somevalues = Numeric.take(repeater, Numeric.cumsum(amask)-1)
Numeric.putmask(anarray, amask, somevalues)
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
More information about the Python-list
mailing list