A B
A B

Reputation: 305

Insert 0s into 2d array

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

Answers (7)

B. M.
B. M.

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

Divakar
Divakar

Reputation: 221684

Using NumPy's broadcasting for a one-liner -

(np.arange(x.size)%2)*(x + np.array([-1,0,1])[:,None])

Explanation -

  1. np.arange(x.size)%2) gives us alternating 0s and 1s.
  2. Use broadcasting with x + np.array([-1,0,1])[:,None]) to get the summations in a vectorized manner.
  3. Use the alternating 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

Mike Müller
Mike Müller

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

ali_m
ali_m

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 row
  • Indexing with None inserts a new dimension of size 1
  • delta[:, None].shape == (3, 1) and x.shape == (4,), so the result of x + delta[:, None] gets broadcast out to a (3, 4) array
  • Finally, y[:, ::2] = 0 fills every other column with zeros.

Upvotes: 4

Jeff Mercado
Jeff Mercado

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

Radek Hofman
Radek Hofman

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

Mike Müller
Mike Müller

Reputation: 85562

In two lines

>>> 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]])

Explanation

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

Related Questions