Wikunia
Wikunia

Reputation: 1592

Numpy or Python for storing dicts

I want to store multidimensional arrays which store something like python dicts. At the moment it looks something like:

a = [[{'col':i,'row':j} for i in range(9)] for j in range(9)]

I know that numpy is perfect if you want to do maths like working with matrices. Things I would like to do fast:

And I don't know how to do that with normal Python lists. Cause something like

idx = [2,3]
print(a[idx]) 

doesn't exist, right? It should outprint {'row':2,'col':3}

Thanks for your ideas and if numpy is the better option: How to create a two dimensional numpy array with values of something like a list type? Is there a way to use dtype=dict ?

Upvotes: 0

Views: 72

Answers (1)

hpaulj
hpaulj

Reputation: 231425

So your a is a list of lists:

In [656]: a = [[{'col':i,'row':j} for i in range(9)] for j in range(9)]
In [657]: a
Out[657]: 
[[{'col': 0, 'row': 0},
  {'col': 1, 'row': 0},
  {'col': 2, 'row': 0},
  ....
In [658]: len(a)
Out[658]: 9
In [659]: a[2][3]
Out[659]: {'col': 3, 'row': 2}

Create an array from that:

In [660]: A=np.array(a, dtype=object)
In [661]: A.shape
Out[661]: (9, 9)
In [662]: A
Out[662]: 
array([[{'row': 0, 'col': 0}, {'row': 0, 'col': 1}, {'row': 0, 'col': 2},
        {'row': 0, 'col': 3}, {'row': 0, 'col': 4}, {'row': 0, 'col': 5},

In [663]: A[2,3]
Out[663]: {'col': 3, 'row': 2}

Not much difference between using a[2][3] and A[2,3] to access one dictionary. Both contain pointers to the same dictionaries

In [664]: A[3,2]['value']=23    # add a key to one; see change in both places
In [666]: A[3,2]
Out[666]: {'col': 2, 'row': 3, 'value': 23}
In [667]: a[3][2]
Out[667]: {'col': 2, 'row': 3, 'value': 23}

I can reshape A,e.g. A1=A.reshape(3,27), but that won't have any effect of the list nesting of a. I could 'flatten' both with:

In [671]: aflat=list(itertools.chain(*a))   # new list, same dict
In [672]: len(aflat)
Out[672]: 81
In [673]: A.ravel().shape     # a view  A.flatten() for copy
Out[673]: (81,)

I could find the dict with the extra key with a list comprehension in either:

In [674]: [a for a in aflat if len(a)==3]
Out[674]: [{'col': 2, 'row': 3, 'value': 23}]
In [675]: [a for a in A.ravel() if len(a)==3]
Out[675]: [{'col': 2, 'row': 3, 'value': 23}]

Sometimes with object dtypes it is possible to perform limited amounts of array math, but that depends on the operation propagating down to objects. I can't think of anything that would do that with dicts.

So for dictionary objects, there isn't much of a difference between using nested lists and object arrays.


The usual rules for array indexing apply:

In [676]: idx=[2,3]
In [677]: A[idx]   # (2,9) array of dict
Out[677]: 
array([[{'row': 2, 'col': 0}, ...{'row': 3, 'col': 8}]], dtype=object)
In [678]: A[tuple(idx)]     # 1 dict
Out[678]: {'col': 3, 'row': 2}

Structured array approach, using fields with the same names as your dictionary keys.

In [681]: dt=np.dtype([('col',int),('row',int)])
In [687]: S = np.array([[(i,j) for i in range(3)] for j in range(3)],dtype=dt)
In [688]: S.shape
Out[688]: (3, 3)
In [689]: S
Out[689]: 
array([[(0, 0), (1, 0), (2, 0)],
       [(0, 1), (1, 1), (2, 1)],
       [(0, 2), (1, 2), (2, 2)]], 
      dtype=[('col', '<i4'), ('row', '<i4')])
In [691]: S[2,2]
Out[691]: (2, 2)
In [692]: S['col']
Out[692]: 
array([[0, 1, 2],
       [0, 1, 2],
       [0, 1, 2]])
In [694]: S[0,2]['row']
Out[694]: 0

Upvotes: 2

Related Questions