Using zip_longest on unequal lists but repeat the last entry instead of returning None

我的梦境 提交于 2021-02-08 12:15:31

问题


There is an existing thread about this Zipping unequal lists in python in to a list which does not drop any element from longer list being zipped

But it's not quite I'm after. Instead of returning None, I need it to copy the previous entry on the list.

Is this possible?

a = ["bottle","water","sky"]
b = ["red", "blue"]
for i in itertools.izip_longest(a,b):
    print i

#result
# ('bottle', 'red')
# ('water', 'blue')
# ('sky', None) 

# What I want on the third line is
# ('sky', 'blue')

回答1:


itertools.izip_longest takes an optional fillvalue argument that provides the value that is used after the shorter list has been exhausted. fillvalue defaults to None, giving the behaviour you show in your question, but you can specify a different value to get the behaviour you want:

    fill = a[-1] if (len(a) < len(b)) else b[-1]
    for i in itertools.izip_longest(a, b, fillvalue=fill):
        print i

(Obviously if the same list is always the shorter one then choosing the fill character is even easier.)




回答2:


You can chain the shorter list with a repeat of its last value. Then using regular izip, the result will be the length of the longer list:

from itertools import izip, repeat, chain

def izip_longest_repeating(seq1, seq2):
    if len(seq1) < len(seq2):
        repeating = seq1[-1]
        seq1 = chain(seq1, repeat(repeating))
    else:
        repeating = seq2[-1]
        seq2 = chain(seq2, repeat(repeating))
    return izip(seq1, seq2)   

print(list(izip_longest_repeating(a, b)))
#  [('bottle', 'red'), ('water', 'blue'), ('sky', 'blue')]    

And here's a version that should work for any iterables:

from itertools import izip as zip # Python2 only

def zip_longest_repeating(*iterables):
    iters = [iter(i) for i in iterables]
    sentinel = object() 
    vals = tuple(next(it, sentinel) for it in iters)
    if any(val is sentinel for val in vals):
        return
    yield vals
    while True:
        cache = vals
        vals = tuple(next(it, sentinel) for it in iters)
        if all(val is sentinel for val in vals):
            return
        vals = tuple(old if new is sentinel else new for old, new in zip(cache, vals))
        yield vals

list(zip_longest_repeating(['a'], ['b', 'c'], ['d', 'r', 'f']))
#  [('a', 'b', 'd'), ('a', 'c', 'r'), ('a', 'c', 'f')]


来源:https://stackoverflow.com/questions/55846806/using-zip-longest-on-unequal-lists-but-repeat-the-last-entry-instead-of-returnin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!