>>> import Numeric
>>> a = Numeric.array([[1,2,3],[4,5,6]])
>>> s = a.shape
>>> for i in range(s[0]):
... for j in range(s[1]):
... print a[i,j]
...
1
2
etc.
>>>
But I'm not sure of the 'best' way to handle this for an array of arbitray
rank (i.e. where 's' is an arbitrary length sequence of non-negative
integers). (I've just started using 2.2.1, so I haven't sussed iterators
yet.)
I'm sure I can come up with some hack. But I'm trying to improve my
programming style. So, anyone any thoughts on this? Do iterators offer a
cute way of handling it? Cheers. TIA.
Duncan Smith
p.s. For one specific problem I will be dealing with very sparse arrays, and
I only really want to consider the cells with non-zero values. So any
problem-specific advice would also be appreciated. (In this case I would
need to return both the value and index of the cell.) :-)
> to iterate over the cells in a Numeric array. No problem if the rank is
> fixed. eg.
...
> But I'm not sure of the 'best' way to handle this for an array of arbitray
> rank (i.e. where 's' is an arbitrary length sequence of non-negative
for item in Numeric.ravel(whatever):
process(item)
> programming style. So, anyone any thoughts on this? Do iterators offer a
> cute way of handling it? Cheers. TIA.
>
> Duncan Smith
>
> p.s. For one specific problem I will be dealing with very sparse arrays,
> and
> I only really want to consider the cells with non-zero values. So any
> problem-specific advice would also be appreciated. (In this case I would
> need to return both the value and index of the cell.) :-)
Numeric probably offers enough magic to let you do this directly, too, but
I don't know it deeply enough. So, if I had a Numeric array suspected to
be "very sparse" and had to return the index-value pairs for nonzero cells,
I'd do something like:
def iterind(shapetuple):
cv = [0]*len(shapetuple)
while 1:
yield tuple(cv)
i = 0
while i<len(cv):
cv[i] += 1
if cv[i] < shapetuple[i]:
break
cv[i] = 0
i += 1
else:
raise StopIteration
or some other way to get all indices into an array of shape shapetuple,
sequentially -- note that memory consumption apart you may trivially
transform this generator into a list-returning function, as always:
def listind(shapetuple):
cv = [0]*len(shapetuple)
results = []
while 1:
results.append(tuple(cv))
i = 0
while i<len(cv):
cv[i] += 1
if cv[i] < shapetuple[i]:
break
cv[i] = 0
i += 1
else:
return results
Once you do have a sequence or iterator for all indices, life's easy,
e.g., here's the generator for the index/value pairs you want:
def iternon0(numarray):
for idx in iterind(Numeric.shape(numarray)):
if numarray[idx]: yield idx, numarray[idx]
or, to have a list instead, for a Numeric array X,
[ (idx, X[idx]) for idx in listind(Numeric.shape(X)) if X[idx] ]
Alex
Alex Martelli wrote:
>> But I'm not sure of the 'best' way to handle this for an array of arbitray
>> rank (i.e. where 's' is an arbitrary length sequence of non-negative
>
> for item in Numeric.ravel(whatever):
> process(item)
>
I'd instead write:
if myarray.iscontiguous:
for item in myarray.flat:
do()
else:
for item in ravel(myarray):
do()
unless you know ahead of time that it's never going to be contiguous. ravel is
I believe a copy operation, much more expensive than a call to the flattened
array (which simply allows the loop to be done with straight pointer
arithmetic underneath).
cheers,
f
Chacking isn't all that expensive, is it?
>>> x=Numeric.array([range(n,n+4) for n in range(3)])
>>> x
array([[0, 1, 2, 3],
[1, 2, 3, 4],
[2, 3, 4, 5]])
>>> f=Numeric.ravel(x)
>>> f
array([0, 1, 2, 3, 1, 2, 3, 4, 2, 3, 4, 5])
>>> x[1,1]=111
>>> x
array([[ 0, 1, 2, 3],
[ 1, 111, 3, 4],
[ 2, 3, 4, 5]])
>>> f
array([ 0, 1, 2, 3, 1, 111, 3, 4, 2, 3, 4, 5])
>>>
Alex
> Fernando Pérez wrote:
> ...
> > ravel is I believe a copy operation, much more expensive than a call to
>
> Chacking isn't all that expensive, is it?
[...]
> >>> f=Numeric.ravel(x)
[...]
> >>> x[1,1]=111
[...]
> >>> f
> array([ 0, 1, 2, 3, 1, 111, 3, 4, 2, 3, 4, 5])
If the array is not contiguous, though, it will make a copy.
John
Alex Martelli wrote:
Thanks! I guess I'd been putting an unnecessary extra if in all my code up to
this point. It looks like ravel does 'the right thing': .flat if possible,
and if not it returns a contiguous copy.
Cheers,
f
(haven't received any of your mails, btw -- must be some blockage...?)
> to this point. It looks like ravel does 'the right thing': .flat if
> possible, and if not it returns a contiguous copy.
Yep, although I don't think it's clearly documented to behave this way.
Alex