Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Iterating over the cells of an array?

0 views
Skip to first unread message

Duncan Smith

unread,
May 11, 2002, 10:53:16 AM5/11/02
to
I am interested in the options for handling the following situation. I want
to iterate over the cells in a Numeric array. No problem if the rank is
fixed. eg.

>>> 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.) :-)


Alex Martelli

unread,
May 11, 2002, 12:01:35 PM5/11/02
to
Duncan Smith wrote:

> 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

Fernando Pérez

unread,
May 12, 2002, 5:15:13 AM5/12/02
to
<posted & mailed>

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

Alex Martelli

unread,
May 12, 2002, 10:38:38 AM5/12/02
to
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?

>>> 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

John J. Lee

unread,
May 12, 2002, 11:38:58 AM5/12/02
to
On Sun, 12 May 2002, Alex Martelli wrote:

> 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

Fernando Pérez

unread,
May 12, 2002, 2:46:18 PM5/12/02
to
<posted & mailed>

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

Alex Martelli

unread,
May 12, 2002, 2:55:26 PM5/12/02
to
Fernando Pérez wrote:
...
> <posted & mailed>

(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

0 new messages