Home > other >  Fill missing values in list based on a condition
Fill missing values in list based on a condition

Time:12-01

I will try to explain my issue with simple example. Let's say I've a list

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , '' , '' , 'Elemnt-6' , 'Elemnt-7']

How can I fill this missing values such that list will become.

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-6' , 'Elemnt-7']

Explination with similar animation.

enter image description here

I've figured out solution. Which is too inefficient for a longer lists & when I've multiple missing values. Here is my logic

from itertools import accumulate

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , '' , '' , 'Elemnt-6' , 'Elemnt-7']

odd_index = lis[::2]
even_index = lis[1::2]

odd_index = list(accumulate(odd_index,lambda x, y: x if y is '' else y))
even_index = list(accumulate(even_index,lambda x, y: x if y is '' else y))

zipper = list(sum(zip(odd_index, even_index [0]), ())[:-1])


print(zipper)

Given me #

['Elemnt-1', 'Elemnt-2', 'Elemnt-3', 'Elemnt-2', 'Elemnt-3', 'Elemnt-6', 'Elemnt-7']

I was looking for a simpler elegant approach to solve this when there are multiple missing values in middle of list.

More examples:

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , '' , '' , '' , 'Elemnt-7']

Need

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-7']

Another example

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , '' , '' , 'Elemnt-6' , 'Elemnt-7', '']

Need

lis = ['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-2' , 'Elemnt-3' , 'Elemnt-6' , 'Elemnt-7' , 'Elemnt-7']

Logically n blank elements should be filled with n back elements

CodePudding user response:

If the missing values are consecutive ones as you showed in the example you can use this.

def fillList(list):
    emptyCount = list.count('')
    for item in list:
        if item == '':
            list[list.index(item)] = list[list.index(item) - emptyCount]
    return list

CodePudding user response:

Using a list comprehension to replace empty values with value of this list two positions before. Repeats until no empty values left.

EDIT : after comments, it appears that it is not always 2 position before, but n blank elements should be filled with n elements before. Answer therefore is still missing something. Replacing lis[index-2] by lis[index-lis.count('')] would not work because it is possible to have multiple set of empty spaces

filler = ['']*len(lis)
while '' in lis :
    filler = [lis[index-2] if value=="" else value for index, value in enumerate(lis)]
    print(filler)
    lis=filler

print(lis)

CodePudding user response:

Because you're looking 2 back to fill the empty spots, we skip the first 2 indeces as there's nothing before theme. Here I define a func that does this:

def filler(l: list):
    for i in range(2, len(l)):
        if l[i] == '':
            l[i] = l[i-2]
    return l

print(filler(['Elemnt-1' , 'Elemnt-2' , 'Elemnt-3' , '' , '' , 'Elemnt-6' , 'Elemnt-7']))
Out:
['Elemnt-1', 'Elemnt-2', 'Elemnt-3', 'Elemnt-2', 'Elemnt-3', 'Elemnt-6', 'Elemnt-7']

CodePudding user response:

You can determine the blank ranges first, then fill them with the previous items.

lst = ['Elment-1' , 'Elment-2' , 'Elment-3' , '' , '' , 'Elment-6' , 'Elment-7', '']
lst_ext = ['p']   lst   ['p']
# boundary of all blank ranges
blank_bound = [idx for idx, (a, b) in enumerate(zip(lst_ext, lst_ext[1:])) \
                   if (a == '' or b == '') and a != b] # [3, 5, 7, 8]
# fill each blank range
for l, r in zip(blank_bound[::2], blank_bound[1::2]):
    assert 2*l-r >= 0, "no enough items before the blank item"
    lst[l:r] = lst[2*l-r:l]
  • Related