problems with duplicating and slicing an array

Yun Mao yunmao at
Fri Jan 21 00:10:02 EST 2005

Hi all,
  Thanks for the help. numarray doesn't provide what I look for either. e.g. 
a = array( [[1,2,3],[4,5,6]] )
I sometimes what this:  a[ [1,0], :],  or even
 a[ [1,0], [0,1] ] , which should give me
[[4, 5], [1,2]]

Because I don't really care about arrays with dimension >2, I did a
little hacking with Numeric.Matrix.Matrix. It is more compatible with
Matlab style slicing (except that the index starts from 0, not 1).
This class automatically does copy, which is what I needed.
Here is the code if somebody is interested (The wordy getAttr part is
due to a "feature" in Numeric.Matrix based on the assumption that
probably nobody is going to inherent it again :) ):

#==========begin code=========
from Numeric import *
from Matrix import Matrix, UserArray
import types

def _isSeq(t):
    if isinstance(t, types.ListType):
        return True
    if (isinstance(t, ArrayType) or isinstance(t, UserArray)):
        return len(t.shape)==1 or \
               (len(t.shape)==2 and t.shape[0]==1)
    return False

class Mat(Matrix):
    def __getitem__(self, index):
        """Matlab style slicing:
        e.g. a[ [3,2], [2,1] ], a[1] 
        if isinstance(index, types.TupleType) and len(index)==1 \
               or _isSeq(index):
                if self.array.shape[0]!=1:
                    return self._rc(self.array.flat).__getitem__(index)
                if not _isSeq(index):
                    return Matrix.__getitem__(self, index)
                return self._rc(take(self, array(index).flat, 1))
        elif isinstance(index, types.TupleType):
            assert len(index)==2
            if not (_isSeq(index[0]) or _isSeq(index[1])):
                return Matrix.__getitem__(self, index)
            r = self.array
            tmp = slice(None, None, None)
            if _isSeq(index[0]):
                r = take(r, array(index[0]).flat,0)
                r = self._rc(r).__getitem__(self, (index[0], tmp))
            if _isSeq(index[1]):
                r = take(r, array(index[1]).flat,1)
                r = self._rc(r).__getitem__( (tmp,index[1]))
            return self._rc(r)
        elif isinstance(index, types.IntType):
            return self.array.flat[index]
        return Matrix.__getitem__(self, index)
    def __getattr__(self, attr):
        if attr == 'A':
            return squeeze(self.array)
        elif attr == 'T':
            return self._rc(Numeric.transpose(self.array))
        elif attr == 'H':
            if len(self.array.shape) == 1:
                self.array.shape = (1,self.array.shape[0])
            return self._rc(Numeric.conjugate(Numeric.transpose(self.array)))
        elif attr == 'I':
            return self._rc(LinearAlgebra.inverse(self.array))
        elif attr == 'real':
            return self._rc(self.array.real)
        elif attr == 'imag':
            return self._rc(self.array.imag)
        elif attr == 'flat':
            return self._rc(self.array.flat)
        elif attr == 'length':
            return max(self.array.shape)
            raise AttributeError, attr + " not found."
#========end code========

> numarray supports matlab style indexing if you pass the ind as an
> array or list of indices (but not a tuple, I found to my surprise).
> As pointed out already, for Numeric you need to use the take function
> >>> from numarray import array
> >>> x = array([1,2,3,4,5,6,7,8,9])
> >>> ind = [3,5,7]
> >>> inda = array(ind)
> >>> indt = tuple(ind)
> >>> x[ind]
> array([4, 6, 8])
> >>> x[inda]
> array([4, 6, 8])
> >>> x[indt]
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> IndexError: too many indices.
> I'm sure the tuple "surprise" is a documented feature.

More information about the Python-list mailing list