1

I want to store a series of differently sized arrays into one "parent" array. Like this:

import numpy as np
    
a1 = np.array([[1,2], [3,4], [5,6]]) 
a2 = np.array([7,3]) 
a3 = np.array([1])

# What I want to do
a_parent = np.ndarray(a1, a2, a3)
    
# Desired output
print(a_parent[0])
>>> [[1 2]
    [3 4]
    [5 6]]
    
print(a_parent[1])
>>> [7 3]
    
print(a_parent[2])
>>> [1]

I know this is possible because when I import Matlab cell data using loadmat from the scipy.io library the data gets converted to a numpy ndarray and it behaves exactly like above. I've looked through the numpy docs and I can't find a working example to show how I could do this myself.

Al-Baraa El-Hag
  • 770
  • 6
  • 15

3 Answers3

2

According to the documentation, an ndarray is:

An array object represents a multidimensional, homogeneous array of fixed-size items.

So you can't have objects of different sizes. You should then just use this:

a_parent = np.array([a1, a2, a3])

np.array allows elements of differents sizes

Nicolas Gervais
  • 33,817
  • 13
  • 115
  • 143
2
In [5]: a1 = np.array([[1,2], [3,4], [5,6]])  
   ...: a2 = np.array([7,3])  
   ...: a3 = np.array([1])       

The best way is to make a 'blank' array of the desired dtype and shape:

In [6]: a_parent = np.empty(3, object)                                                               
In [7]: a_parent                                                                                     
Out[7]: array([None, None, None], dtype=object)

and 'fill' it from a list of the desired arrays (or other objects):

In [13]: a_parent[:] = [a1,a2,a3]                                                                    
In [14]: a_parent                                                                                    
Out[14]: 
array([array([[1, 2],
       [3, 4],
       [5, 6]]), array([7, 3]),
       array([1])], dtype=object)

I'm sure loadmat uses this method.

Passing the list directly to np.array may work, but v1.19 wants us to include the object dtype:

In [10]: np.array([a1,a2,a3])                                                                        
/usr/local/bin/ipython3:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  #!/usr/bin/python3
Out[10]: 
array([array([[1, 2],
       [3, 4],
       [5, 6]]), array([7, 3]),
       array([1])], dtype=object)

This does not work if the arrays are all the same shape:

In [11]: np.array([a1,a1])                                                                           
Out[11]: 
array([[[1, 2],
        [3, 4],
        [5, 6]],

       [[1, 2],
        [3, 4],
        [5, 6]]])

And for some shape combinations we get an error.

In [15]: a_parent[:] = [a3,a3,a3]                                                                    
In [16]: a_parent                                                                                    
Out[16]: array([array([1]), array([1]), array([1])], dtype=object)
hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • This is perfect. Though how do I append a new array to a_parent? – Al-Baraa El-Hag Jul 25 '20 at 04:08
  • There's a whole family of `np.concatenate` and `stack` functions that create a new array from a list of arrays. But they can be picky about matching dimensions. Better to append to a list. – hpaulj Jul 25 '20 at 04:29
1

You can create a list and the use np.array just like this :

a_parent = np.array([a1, a2, a3], dtype=object)
Luke B
  • 1,143
  • 1
  • 11
  • 22