Iterating over the cells of an array?

Alex Martelli aleax at aleax.it
Sat May 11 12:01:35 EDT 2002


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




More information about the Python-list mailing list