johnhenry
johnhenry

Reputation: 1333

Python - extending and filling list with zeros to match another list

I have a list a with a few elements. I have another list b with more elements. I need to extend a to match b in size, using zeros to fill. In the new list that will come out, the original a sits in a position determined by b, as explained by example in the following.
Small example of my situation:

a = [3, 4, 5]

b = [1.2, 2.5, 3.7, 4.3, 5.1, 6.3, 7.3, 8.9]

I need

[0, 0, 3, 4, 5, 0, 0, 0]

The first non-zero element is in third position here, to match where b becomes equal or greater than 3, and similarly the last non-zero element is in fifth position as a result of the comparison with b.

The final output is always len(b); if there are too many zeros at the start to fit all of a, then elements from a are dropped.

Upvotes: 2

Views: 3244

Answers (4)

whackamadoodle3000
whackamadoodle3000

Reputation: 6748

You could try this with list comprehensions

a = [3, 4, 5]
b = [1.2, 2.5, 3.7, 4.3, 5.1, 6.3, 7.3, 8.9]
num=[c for c,e in enumerate(b) if e>=a[0]][0]
c=[0 for e in range(num)]+a+[0 for e in range(len(b)-num-len(a))]
print(c)

Upvotes: 0

aprasanth
aprasanth

Reputation: 1099

Try this

for i in b:
    if int(i) not in a:
        a.insert(b.index(i),0)

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1121744

Use bisection to find the first position in b greater or equal to a[0], with the bisect module

import bisect

def zero_pad(a, b):
    pos = bisect.bisect(b, a[0])
    remainder = len(b) - len(a) - pos
    return ([0] * pos + a + [0] * remainder)[:len(b)]

Bisection lets you find the point in O(logN) time.

An alternative is to use a generator function; loop over b and yield 0s until an equal or larger value to a[0] is found, then yield a until exhausted and go back to zeros:

def zero_pad_gen(a, b, _sentinel=object()):
    a = iter(a)
    nexta = next(a, _sentinel)
    for bval in b:
        if nexta is _sentinel or bval < nexta:
            yield 0
        else:
            yield nexta
            nexta = next(a, _sentinel)

Demo:

>>> a = [3, 4, 5]
>>> b = [1.2, 2.5, 3.7, 4.3, 5.1, 6.3, 7.3, 8.9]
>>> zero_pad(a, b)
[0, 0, 3, 4, 5, 0, 0, 0]
>>> list(zero_pad_gen(a, b))
[0, 0, 3, 4, 5, 0, 0, 0]

and for edge cases; b too short, dropping values from a:

>>> zero_pad(a, b[:-4])
[0, 0, 3, 4]
>>> list(zero_pad_gen(a, b[:-4]))
[0, 0, 3, 4]

First value of b matching:

>>> zero_pad([1, 2] + a, b)
[1, 2, 3, 4, 5, 0, 0, 0]
>>> list(zero_pad_gen([1, 2] + a, b))
[1, 2, 3, 4, 5, 0, 0, 0]

Upvotes: 1

Prasad
Prasad

Reputation: 6034

a = [3, 4, 5]
b = [1.2,2.5,3.7,4.3,5.1,6.3,7.3,8.9]

b.sort()  # Ensure they are sorted

start_zero_till = len(b) - len(a)
for i in range(len(b)):
    if a[0] < b[i]:
        start_zero_till = i
        break

revised_a = [0] * start_zero_till
revised_a.extend(a)
revised_a.extend([0] * (len(b) - len(revised_a)))

print(revised_a)

Upvotes: 1

Related Questions