Srikanth
Srikanth

Reputation: 829

Howto create python arrays with a "struct" as data-type and custom methods

I am migrating some of my code from MATLAB. I was wondering if a functionality exists where I define a certain class (3d vector) and I could define arrays (or lists?) of this class. I would like to be able to use slicing operations on this array.

For example, MATLAB has this functionality:

obj = class(s,'class_name') 

creates an array of class class_name objects using the struct s as a pattern to determine the size of obj.

I understand that numpy offers everything I need for array operations. I am trying to learn right now and this is just and example. So, I would like to do this without numpy arrays.

I might be completely wrong in approaching it this way, so please feel free to suggest if there are any better methods out there to do this. I was looking into subclassing ndarray, but that seems like I would just be creating an array again. Any suggestions are greatly appreciated.

My code so far:

class vector3d(object):

    def __init__(self,*args):
        nargs = len(args);
        if(nargs == 0): # Null Vector
            self.x = None; self.y = None; self.z = None;
        elif(nargs==1):
            if (type(args[0]) is vector3d):
                self = args[0];
            elif(type(args[0]) is np.ndarray):
                Vec = args[0];
                if (np.shape(Vec)[0]==1 or np.shape(Vec)[1]==1):
                    if (np.shape(Vec) == (3,1)):
                        self.x = Vec[0,0]; self.y = Vec[1,0]; 
                        self.z = Vec[2,0];

                    elif (np.shape(Vec) == (1,3)):
                        self.x = Vec[0,0]; self.y = Vec[0,1]; 
                        self.z = Vec[0,2];
                    else:
                        raise Exception('Wrong Type of Inputs');
                else:
                    raise Exception('Wrong Type of Inputs');

VecArray = np.ndarray((10,), dtype=np.object);
print np.shape(VecArray);
for i in range(10):
    print i;
    VecArray[i] = vector3d(np.random.rand(3,1));

After running the code, when I try the following:

>>> VecArray[1].x

>>> 0.36923808713820772

>>> VecArray[1:5].x

AttributeError                            Traceback (most recent call last)
<ipython-input-92-899463ad0461> in <module>()
----> 1 VecArray[1:5].x

AttributeError: 'numpy.ndarray' object has no attribute 'x'

I understand that I could make lists of the object. I should have been more specific. I would like to get an indexable variable as output. For example, something that does not give the above as error.

Upvotes: 0

Views: 2235

Answers (2)

Imanol Luengo
Imanol Luengo

Reputation: 15909

You can use numpy datatypes: http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html

>>> dt = np.dtype([('x', np.int32), ('y', np.int32), ('z', np.int32)])
>>> x = np.array([(1, 2, 3), (3, 2, 1)], dtype = dt)
>>> print x 
[(1, 2, 3) (3, 2, 1)]
>>> print x['x'], x['y'], x['z']
[1 3] [2 2] [3 1]
>>> print x[0]['x']
1

Extending example to add some numpy/matlab indexing:

>>> x = np.array([(1, 2, 3), (4, 5, 6), (7, 8, 9)], dtype = dt)
>>> print x[1:]['x']
[4 7]

You can notice that it omits the first element in the X axis (the 1)


EDIT to add some information about how to subclass using custom data type. Using the example in answer from a similar question https://stackoverflow.com/a/5154869/764322 and sightly modifying it:

>>> class Data(np.ndarray):
        def __new__(cls, inputarr):
            dt = np.dtype([('x', np.int32), ('y', np.int32), ('z', np.int32)])
            obj = np.asarray(inputarr, dtype = dt).view(cls)
            return obj

        def remove_some(self, col, val):
            return self[self[col] != val]

>>> a = Data([(1,2,3), (4,5,6), (7,8,9)])
>>> print a
[(1, 2, 3) (4, 5, 6) (7, 8, 9)]
>>> print a.remove_some('x', 4)
[(1, 2, 3) (7, 8, 9)]

Upvotes: 4

jonrsharpe
jonrsharpe

Reputation: 122091

I think what you want is numpy.empty:

>>> import numpy as np
>>> a = np.empty((2, 2), dtype=np.object_)
>>> a
array([[None, None],
       [None, None]], dtype=object)

This creates an empty array with the specified shape (in this case 2x2) and dtype (in this case, generic objects).

Upvotes: 0

Related Questions