1

I am attempting to use a class that strings together several instances of another class as a numpy array of objects. I want to be able to concatenate attributes of the instances that are contained in the numpy array. I figured out a sloppy way to do it with a bunch of for loops, but I think there must be a more elegant, pythonic way of doing this. The following code does what I want, but I want to know if there is a cleaner way to do it:

import numpy as np


class MyClass(object):

    def __init__(self):
        self.a = 37.
        self.arr = np.arange(5)


class MyClasses(object):

    def __init__(self):
        self.N = 5 
        # number of MyClass instances to become attributes of this
    # class 

    def make_subclas_arrays(self):
        self.my_class_inst = np.empty(shape=self.N, dtype="object") 
        for i in range(self.N):
            self.my_class_inst[i] = MyClass()

    def concatenate_attributes(self):
        self.a = np.zeros(self.N)
        self.arr = np.zeros(self.N * self.my_class_inst[0].arr.size)
        for i in range(self.N):
            self.a[i] = self.my_class_inst[i].a
            slice_start = i * self.my_class_inst[i].arr.size
            slice_end = (i + 1.) * self.my_class_inst[i].arr.size
            self.arr[slice_start:slice_end] = ( 
        self.my_class_inst[i].arr )

my_inst = MyClasses()
my_inst.make_subclas_arrays()
my_inst.concatenate_attributes()

Edit: Based on the response from HYRY, here is what the methods look like now:

def make_subclass_arrays(self):
    self.my_class_inst = np.array([MyClass() for i in range(self.N)])

def concatenate_attributes(self):
    self.a = np.hstack([i.a for i in self.my_class_inst])
    self.arr = np.hstack([i.arr for i in self.my_class_inst])
1
  • This change cut the necessary number of lines of code in half. Commented Feb 11, 2012 at 16:13

2 Answers 2

1

you can use numpy.hstack() to concatenate arrays:

def concatenate_attributes(self):
    self.a = np.hstack([o.a for o in self.my_class_inst])
    self.arr = np.hstack([o.arr for o in self.my_class_inst])

See Also

vstack : Stack arrays in sequence vertically (row wise). dstack : Stack arrays in sequence depth wise (along third axis). concatenate : Join a sequence of arrays together.

Sign up to request clarification or add additional context in comments.

1 Comment

This is beautiful! This greatly improves the pythonicity of my code! Thanks.
1

For the latter function I would recommend this:

init = []
ContainerClass.arr = np.array([init + Array(myclass.arr) for myclass in self.my_class_inst])

typecast numpy array to normal array, catenate and typecast it back. Assuming now that you have simple 1D arrays. I don't remember by heart if numpy array has catenation function. You can use that instead of '+' sign and save the trouble of typecasting.

For the first you have the simplest form I can think of, although I usually use normal arrays instead of numpy ones for objects.

If you want to be really clever you can create an __add__ function for both of the classes. Then you can use '+' sign to add classes. a + b calls a.__add__(b). Now you would have to create functions that have following properties

  1. MyClass + MyClass returns new MyClasses instance with a and b inside
  2. MyClasses + MyClass adds MyClass to MyClasses in a way you want

Now if a,b,c,d are myClass instances, a+b+c+d should return MyClasses -class which contains MyClass instances a,b,c and d and their combined arrays. This would be the pythonic way, although its a bit too complicated in my taste.

edit:

Ok, sorry my bad. I did not have python when I wrote the code. This is the correct version:

init = []
my_inst.arr = np.array([init + list(myclass.arr.flat) for myclass in my_inst.my_class_inst]).flatten()

This is what I meant with the __add__ (and the pythonic way... regadless of its complicatedness):

import numpy as np

class MyClass(object):

    def __init__(self):
        self.a = 37.
        self.arr = np.arange(5)

    def __add__(self, classToAdd):
        a = MyClasses() + self + classToAdd
        return a


class MyClasses(object):

    def __init__(self):
        self.N = 0
        self.my_class_inst = np.array([])
        self.a = np.array([])
        self.arr = np.array([])

    def __add__(self, singleClass):
        self.my_class_inst = np.hstack([self.my_class_inst, singleClass])
        self.a = np.hstack([self.a, singleClass.a])
        self.arr = np.hstack([self.arr, singleClass.arr])
        self.N = self.my_class_inst.shape[0]
        return self

#add_test = MyClass() + MyClass()
add_test = np.sum([MyClass() for i in range(5)])

print add_test.a, add_test.arr, add_test.N
print add_test.__class__, add_test.my_class_inst[0].__class__

2 Comments

Can you point to a good reference for what ContainerClass is? I am having trouble understanding what it can do for my purpose.
hups, sorry. ContainerClass is supposed to be instance of MyClasses (my_inst in your example). Also there was also other dimension problems... now fixed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.