a
is 2x1 array containing 2 objects, both of class A
:
In [162]: a
Out[162]:
array([[<__main__.A object at 0xab20030c>],
[<__main__.A object at 0xab20034c>]], dtype=object)
I can cast the method call as function with:
def foo(an_A):
return an_A.methodA()
In [164]: a.shape
Out[164]: (2, 1)
In [165]: foo(a[0,0])
Out[165]:
array([[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>]], dtype=object)
which is another 2x1 array, this time containing C
objects. Is there a particular reason why these are all (2,1) as opposed to (2,)?
frompyfunc
is a handy tool for applying a function to all elements of any array, especially when both inputs and outputs are object arrays:
In [166]: f=np.frompyfunc(foo,1,1)
In [167]: f(a)
Out[167]:
array([[ array([[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>]], dtype=object)],
[ array([[<__main__.C object at 0xab20096c>],
[<__main__.C object at 0xab2003cc>]], dtype=object)]], dtype=object)
Like a
, this is (2,1), but now it contains the 2 (2,1) C arrays.
I can convert it into a (4,1) array of C
objects with.
In [176]: np.concatenate(f(a)[:,0])
Out[176]:
array([[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>],
[<__main__.C object at 0xab20096c>],
[<__main__.C object at 0xab2003cc>]], dtype=object)
np.r_[tuple(f(a)[:,0])]
also does this. https://stackoverflow.com/a/42091616/901925
We could apply the concatenate to the (2,1) f(a)
array, but the result is messier.
You could also use ndenumerate
to produce the same thing as f(a)
. First you need to create an array that will receive the individual foo(x)
results:
In [186]: res=np.empty(a.shape, object)
In [187]: for idx,x in np.ndenumerate(a):
...: res[idx] = foo(x)
...:
In [188]: res
Out[188]:
array([[ array([[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>]], dtype=object)],
[ array([[<__main__.C object at 0xab20096c>],
[<__main__.C object at 0xab2003cc>]], dtype=object)]], dtype=object)
On a 1d a
or a[:,0]
we can use a simple list comprehension:
In [189]: [foo(x) for x in a[:,0]]
Out[189]:
[array([[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>]], dtype=object),
array([[<__main__.C object at 0xab20096c>],
[<__main__.C object at 0xab2003cc>]], dtype=object)]
In [190]: np.array([foo(x) for x in a[:,0]])
Out[190]:
array([[[<__main__.C object at 0xab2001cc>],
[<__main__.C object at 0xab2002ec>]],
[[<__main__.C object at 0xab20096c>],
[<__main__.C object at 0xab2003cc>]]], dtype=object)
In [191]: _.shape
Out[191]: (2, 2, 1)
I'm tempted to go back a make foo
return an_A.method()[:,0]
, or simplify a
:
In [192]: a1 = np.array([ A(2,3 , np.array([C(2,3), C(5,6) ])),
...: A(4,5 , np.array([C(1,2),C(9,7)]))
...: ])
In [195]: np.array([foo(x) for x in a1]) # (2,2) result
Out[195]:
array([[<__main__.C object at 0xab1aefcc>,
<__main__.C object at 0xab1ae94c>],
[<__main__.C object at 0xab1ae0cc>,
<__main__.C object at 0xab1eb2ac>]], dtype=object)
If I give your classes repr
methods
def __repr__(self):
return 'A<{0.a},{0.b},{0.the_c}>'.format(self)
def __repr__(self):
return 'C<{0.t},{0.y}>'.format(self)
then a
displays as
array([[A<2,3,[[C<2,3>]
[C<5,6>]]>],
[A<4,5,[[C<1,2>]
[C<9,7>]]>]], dtype=object)
and f(a)
as
[[array([[C<2,3>],
[C<5,6>]], dtype=object)]
[array([[C<1,2>],
[C<9,7>]], dtype=object)]]
With a similar repr for B
, b = B(1,2,a)
displays as
B<1,2,[[A<2,3,[[C<2,3>]
[C<5,6>]]>]
[A<4,5,[[C<1,2>]
[C<9,7>]]>]]>
and B(1,2,fA(a)).the_a
as (the equivalent of implementing the B.evaluate
with f
:
[[array([[C<2,3>],
[C<5,6>]], dtype=object)]
[array([[C<1,2>],
[C<9,7>]], dtype=object)]]