Reputation: 1592
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:
accessing by multidimensional indexes
changing values using multidimensional indexes
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
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