-2

I have a python list called Headings:

Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]

I want to get is so the None values are replaced with the String or Number that precedes and is the the closest to the None value like this:

Headings=['Doug', 'Doug', 'Doug', 'Doug', 'Doug', 1234, 1234, 1234, 'Mike', 'Mike']

How do I do so?

Also with the initial Headings List..

Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]

How to I get an index of where a string or number starts and where it ends?

For example I need index of where 'Doug' is and the index of the None that precedes 1234. Likewise I need the index where 1234 is and the index of the last None before 'Mike'.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343

4 Answers4

0

Use a generator that returns the last not-None value when encountering None:

def replace_none(lst):
    last = None
    for item in lst:
        if item is None:
            yield last
        else:
            last = item
            yield item

Simply call list() on the generator if you need a list:

>>> def replace_none(lst):
...     last = None
...     for item in lst:
...         if item is None:
...             yield last
...         else:
...             last = item
...             yield item
... 
>>> Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]
>>> list(replace_none(Headings))
['Doug', 'Doug', 'Doug', 'Doug', 'Doug', 1234, 1234, 1234, 'Mike', 'Mike']
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
0
from itertools import accumulate

Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]

Headings = accumulate(Headings,lambda x, y: x if y is None else y)
['Doug', 'Doug', 'Doug', 'Doug', 'Doug', 1234, 1234, 1234, 'Mike', 'Mike']

If you want the indexes also you can use a variation of this answer:

from itertools import chain
Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]

def replace_none(l):
    inds = ((ind, ele) for ind, ele in enumerate(Headings) if ele is not None)
    start_i, start_ele = next(inds)
    yield start_i
    yield from chain.from_iterable(((i-1, i) for i, _ in inds))
    for ind, ele in enumerate(l):
        if ele is None:
            Headings[ind] = start_ele
        else:
            start_ele = ele

Output:

print(list(replace_none(Headings)))

print(Headings)
[0, 4, 5, 7, 8]
['Doug', 'Doug', 'Doug', 'Doug', 'Doug', 1234, 1234, 1234, 'Mike', 'Mike']

If the first element might be None and you want the previous None before the first element that is not None:

def replace_none(l):
    inds = ((ind, ele) for ind, ele in enumerate(Headings) if ele is not None)
    start_i, start_ele = next(inds)
    if start_i == 0:
        yield start_i
    else:
        yield from (start_i-1, start_i)
    yield from chain.from_iterable(((i-1, i) for i, _ in inds))
    for ind, ele in enumerate(l):
        if ele is None:
            Headings[ind] = start_ele
        else:
            start_ele = ele
Community
  • 1
  • 1
Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • If this is the answer, shouldn't we close this question as a dup of [this one](http://stackoverflow.com/questions/31256159/replace-none-in-list-with-leftmost-non-none-value) where I gave the accumulate answer and you gave an iterative one? – DSM Sep 11 '15 at 17:13
0

You can use a generator for this purpose. A great explanation of how they work was posted here: What does the "yield" keyword do in Python?

That said, a concise method for the first part of your problem is as follows:

def replace_none(lis):
    last = None
    for item in lis:
        last = last if item is None else item
        yield last

You can then cast the generator to a list if required, as explained in other answers like so:

Headings = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None]
list(replace_none(Headings))
Community
  • 1
  • 1
abali96
  • 24
  • 1
  • 5
0

This solution is without yield - am wondering if I am missing any complexity in the program?

def replaceNone(myList):
    
    for idx,value in enumerate(myList):
        if value == None:
            myList[idx] = myList[idx-1]
            
    return myList

myList = ['Doug', None, None, None, None, 1234, None, None, 'Mike', None] 
print(replaceNone(myList))

['Doug', 'Doug', 'Doug', 'Doug', 'Doug', 1234, 1234, 1234, 'Mike', 'Mike']
David Buck
  • 3,752
  • 35
  • 31
  • 35
Vidya
  • 23
  • 5