Reputation: 305
I have an array x
:
x = [0, -1, 0, 3]
and I want y
:
y = [[0, -2, 0, 2],
[0, -1, 0, 3],
[0, 0, 0, 4]]
where the first row is x-1
, the second row is x
, and the third row is x+1
. All even column indices are zero.
I'm doing:
y=np.vstack(x-1, x, x+1)
y[0][::2] = 0
y[1][::2] = 0
y[2][::2] = 0
I was thinking there might be a one-liner to do this instead of 4.
Upvotes: 13
Views: 1311
Reputation: 18668
a short version : [[-1],[0],[1]]*(x!=0)+x
.
[[-1],[0],[1]]*(x!=0)
is
|-1 |-1 | 0 -1 0 -1 |
dot( |0 , [True False True False] ) = dot( |0 , [ 1 0 1 0] ) = | 0 0 0 0 | = z
|1 |1 | 0 1 0 1 |
z + x is : (braodcasting)
| 0 -1 0 -1 | | 0 -1 0 3 | | 0 -2 0 2 |
| 0 0 0 0 | + | 0 -1 0 3 | = | 0 -1 0 3 |
| 0 1 0 1 | | 0 -1 0 3 | | 0 0 0 4 |
Upvotes: 0
Reputation: 221684
Using NumPy's broadcasting for a one-liner -
(np.arange(x.size)%2)*(x + np.array([-1,0,1])[:,None])
Explanation -
np.arange(x.size)%2)
gives us alternating 0s
and 1s
.x + np.array([-1,0,1])[:,None])
to get the summations in a vectorized manner.1s
and 0s
created in step-1
to set or not-set the columns of the summed array in step-2 and thus produce the final output.Sample run -
In [40]: x
Out[40]: array([ 0, -1, 0, 3])
In [41]: (np.arange(x.size)%2)*(x + np.array([-1,0,1])[:,None])
Out[41]:
array([[ 0, -2, 0, 2],
[ 0, -1, 0, 3],
[ 0, 0, 0, 4]])
Upvotes: 3
Reputation: 85562
A one-liner in NumPy:
>>> x = np.array([0, -1, 0, 3])
>>> y = np.vstack((x-1, x, x+1)) * np.resize([0, 1], len(x))
>>> y
array([[ 0, -2, 0, 2],
[ 0, -1, 0, 3],
[ 0, 0, 0, 4]])
Upvotes: 1
Reputation: 74252
Or alternatively, use broadcasting:
import numpy as np
x = np.array([0, -1, 0, 3])
delta = np.array([-1, 0, 1])
y = x + delta[:, None]
y[:, ::2] = 0
print(repr(y))
# array([[ 0, -2, 0, 2],
# [ 0, -1, 0, 3],
# [ 0, 0, 0, 4]])
delta
specifies how much to add/subtract from each rowNone
inserts a new dimension of size 1delta[:, None].shape == (3, 1)
and x.shape == (4,)
, so the result of x + delta[:, None]
gets broadcast out to a (3, 4)
arrayy[:, ::2] = 0
fills every other column with zeros.Upvotes: 4
Reputation: 134581
Personally, I would have viewed this differently. You're not adding 1
to x
, you're adding [0, 1, 0, 1]
.
x = np.array([0, -1, 0, 3])
d = np.resize([0, 1], len(x))
y = np.vstack((x-d, x, x+d))
Upvotes: 1
Reputation: 527
One-liner without numpy
:
x = [0, -1, 0, 3]
y = [ [(x[i] - j if i%2 else 0) for i in range(4)] for j in (1,0,-1)]
gives following y
:
[[0, -2, 0, 2], [0, -1, 0, 3], [0, 0, 0, 4]]
Upvotes: 2
Reputation: 85562
>>> x = np.array([0, -1, 0, 3])
>>> y = np.vstack((x-1, x, x+1))
>>> y[:,::2] = 0
>>> y
array([[ 0, -2, 0, 2],
[ 0, -1, 0, 3],
[ 0, 0, 0, 4]])
y[:, ::2]
gives the full first dimension. i.e all rows and every other entry form the second dimension, i.e. the columns:
array([[-1, -1],
[ 0, 0],
[ 1, 1]])
This is different from:
y[:][::2]
because this works in two steps. Step one:
y[:]
gives a view of the whole array:
array([[-1, -2, -1, 2],
[ 0, -1, 0, 3],
[ 1, 0, 1, 4]])
Therefore, step two is doing essentially this:
y[::2]
array([[-1, -2, -1, 2],
[ 1, 0, 1, 4]])
It works along the first dimension. i.e. the rows.
Upvotes: 10