Reputation: 1
I am trying to make an array, which includes the same number multiple times, but if I change it in any place, it should change everywhere. Like with lists:
a = b = [1]
>>> a.append(1)
>>> print(b)
>>> [1, 1]
So I want an array like this:
number = 10
arr = numpy.zeros((10, 10))
arr[0][0] = number
arr[1][1] = number
arr[0][0] += 1
print(arr[1][1])
Here it should output "11". So is there a way to have multiple references to a number? I know you could replace all the 10s with 11s, but firstly this would be too inefficient, secondly this could mess things up since another number may be coincidentally a 10 too.
Thanks.
Upvotes: 0
Views: 697
Reputation: 53079
A zero dimensional numpy array behaves in many respects like a mutable number:
>>> import numpy as np
>>>
>>> a = 2.0 # ordinary immutable number
>>> am = np.array(2.0) # "mutable number"
>>>
>>> A = np.array([[a, a, am, a], [am, am, a, a]], dtype=object)
>>> A
array([[2.0, 2.0, array(2.), 2.0],
[array(2.), array(2.), 2.0, 2.0]], dtype=object)
That's a bit ugly, so below I'll convert to float before printing:
>>> A.astype(float)
array([[2., 2., 2., 2.],
[2., 2., 2., 2.]])
These twos are not all equal, The top left is immutable
>>> A[0, 0] += 1
Assigning to it only directly addressed cell is affected:
>>> A.astype(float)
array([[3., 2., 2., 2.],
[2., 2., 2., 2.]])
>>> a
2.0
The third two is mutable
>>> A[0, 2] -= 1
Assigning to it all references are affected:
>>> A.astype(float)
array([[3., 2., 1., 2.],
[1., 1., 2., 2.]])
>>> am
array(1.)
Direct assignment requires [()]
syntax:
>>> A[0, 2][()] = 1.5
>>> am
array(1.5)
Otherwise the link will break:
>>> A[0, 2] = 1.8
>>> A.astype(float)
array([[3. , 2. , 1.8, 2. ],
[1.5, 1.5, 2. , 2. ]])
In a comment OP specifies the following desired behavior:
If the mutable number am
occurs k
times in A
, then in A * 3
the mutable number should be multiplied with 3**k
, not 3
.
We can get this behavior using the inplace (*=
) operator and some trickery; if we want to preserve the original A
, we must first make a copy:
Because numpy
s copying machinery normalizes our 0D arrays away, some more trickery is required to make a good copy:
>>> import copy
>>>
>>> B = np.empty_like(A)
>>> B.ravel()[...] = copy.deepcopy((*A.ravel(),))
Now do the inplace multiplication on the copy:
>>> import operator as op
>>>
>>> C = np.frompyfunc(op.imul, 2, 1)(B, 3)
>>>
>>> A
array([[2.0, 2.0, array(2.), 2.0],
[array(2.), array(2.), 2.0, 2.0]], dtype=object)
>>> C
array([[6.0, 6.0, array(54.), 6.0],
[array(54.), array(54.), 6.0, 6.0]], dtype=object)
Note that B
will contain some useless hybrid data in the end and should be discarded.
>>> B
array([[2.0, 2.0, array(54.), 2.0],
[array(54.), array(54.), 2.0, 2.0]], dtype=object)
>>> del B
Final note: this is more trickery than sane programming, so please regard it as a can-be-done rather than a should-be-done.
Upvotes: 1