Normally numpy forces the left and right side of an assignment to match, so for example if I do a[:] = b
, b
must be the same shape or broadcast to the same shape as a
. But there seems to be an exception to that rule:
>>> a = np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = a.copy()
>>> a[[0,1,2]] = b[::2]
>>> a
array([0, 2, 4, 3, 4, 5, 6, 7, 8, 9])
>>> a[np.arange(10)] = b[:2]
>>> a
array([0, 1, 0, 1, 0, 1, 0, 1, 0, 1])
It seems to only work with 1d arrays and only if there is fancy indexing on the left side of the assignment, but I haven't been able to find documentation for this behavior anywhere. Is this behavior documented, if so where, and also can someone give an example of when it might be useful?
Update:
It seems that the numpy flatiter type behaves this way too, is there some connection between flatiter and fancy indexing that I don't know about?
>>> a.flat = [10,11]
>>> a
array([10, 11, 10, 11, 10, 11, 10, 11, 10, 11])
>>> a.flat[:] = [2,3,4]
>>> a
array([2, 3, 4, 2, 3, 4, 2, 3, 4, 2])
>>> a.flat = range(100)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
I think this behavior is modeled on R and its ancestor S/S-plus. That's how list assignment ("vector" assignment) works there, and it's called "recycling". The R project website talks about it, but I found a more illuminating explanation at this link. In R, a vector is a collection of measurements, so it makes sense to pad or trim it the way it does. How much of this logic has made it to numpy, and why, is still a good question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With