Reputation: 2028
Main array doesn't update values during assigning method inside np.nditer when iterative array is used as subarray
array = np.arange(20)
with np.nditer(array[np.nonzero(array)],
op_flags=['readwrite']) as it:
for x in it:
x[...] = 5
array
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
Subarray assigns great without np.nditer
array[np.nonzero(array)] = 5
array
array([0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
There is a workaround over by using temporary array.
tmp_array = array[np.nonzero(array)]
array = np.arange(20)
with np.nditer(tmp_array,
op_flags=['readwrite']) as it:
for x in it:
x[...] = 5
array[np.nonzero(array)] = tmp_array
array
array([0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
Upvotes: 0
Views: 365
Reputation: 231425
In [48]: arr = np.arange(20)
...: with np.nditer(arr[np.nonzero(arr)],
...: op_flags=['readwrite']) as it:
...: for x in it:
...: x[...] = 5
...: arr
Out[48]:
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19])
This doesn't change arr
because it isn't iterating on arr
. Instead it is doing:
In [49]: arr = np.arange(20)
...: arr1 = arr[np.nonzero(arr)]
...: with np.nditer(arr1,
...: op_flags=['readwrite']) as it:
...: for x in it:
...: x[...] = 5
...: arr1
Out[49]: array([5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
In [50]: _.shape
Out[50]: (19,)
arr1
isn't a view
of arr
, it is selection, a new array without shared data buffer.
If you want to modify arr
, you have to iterate on it, not a copy. Do the test, or anything fancy, inside the loop.
In [51]: arr = np.arange(20)
...: with np.nditer(arr,
...: op_flags=['readwrite']) as it:
...: for x in it:
...: if x > 0:
...: x[...] = 5
...: arr
Out[51]: array([0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
But why are you using nditer
? You already know how to do this kind of selective assignment, using the non-iterative methods:
array[np.nonzero(array)] = 5
In this case the assignment =
immediately follows the advanced indexing, and Python uses array.__setitem__
rather than arr.__getitem__
.
Iterating on a slice, a view
does change the source:
In [52]: arr = np.arange(20)
...: with np.nditer(arr[5:],
...: op_flags=['readwrite']) as it:
...: for x in it:
...: x[...] = 5
...: arr
Out[52]: array([0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5])
Upvotes: 1