Vince Jerald Villamora Vince Jerald Villamora - 28 days ago 14
Python Question

Pythonic way of copying a non-zero value list to fill in the zeroes of another list

I have a list

a = [2, 5, 6, 3, 9]


here's what the other list should look like

b = [0, 7, 9, 3, 3, 0, 4, 0, 3, 1, 0, 0, 4]


what I'm trying to achieve is to copy the first list in to the second list so it replaces the zeroes like so

c = [2, 7, 9, 3, 3, 5, 4, 6, 3, 1, 3, 9, 4]


If there are too many zeroes in
b
, it will just be ignored and will stay 0 in
c
and if the there are too few zeroes in
b
, some values in a would simply not be carried over or copied to
c


edit

and is there a way to do this to fill a list like this

b = [[0, 3, 9, 1, 3]
[3, 3, 4, 2, 0]
[3, 5, 5, 0, 2]
[0, 0, 3, 8, 9]
[1, 2, 3, 4, 5]]


so that
c
will be

c = [[2, 3, 9, 1, 3]
[3, 3, 4, 2, 5]
[3, 5, 5, 6, 2]
[3, 9, 3, 8, 9]
[1, 2, 3, 4, 5]]

DSM DSM
Answer Source

One way would be to use iter to create an object giving each element in a one-by-one, and then use an ordinary listcomp:

>>> a = [2, 5, 6, 3, 9]
>>> b = [0, 7, 9, 3, 3, 0, 4, 0, 3, 1, 0, 0, 4]
>>> fill = iter(a)
>>> c = [x if x != 0 else next(fill) for x in b]
>>> c
[2, 7, 9, 3, 3, 5, 4, 6, 3, 1, 3, 9, 4]

As @bulbus notes, this will raise a StopIteration exception if you don't have enough zeros to fill. You could use the default value for next, e.g. next(fill, 0) if you want to avoid that.

For your 2D case, the same approach works, we just need to change the listcomp:

>>> fill = iter(a)
>>> b = [[0, 3, 9, 1, 3], [3, 3, 4, 2, 0], [3, 5, 5, 0, 2], [0, 0, 3, 8, 9], [1, 2, 3, 4, 5]]
>>> c = [[x if x != 0 else next(fill) for x in row] for row in b]
>>> c
[[2, 3, 9, 1, 3], [3, 3, 4, 2, 5], [3, 5, 5, 6, 2], [3, 9, 3, 8, 9], [1, 2, 3, 4, 5]]