[灵感来自this question]
假设我有两个列表:
list1 = ['tom', 'mary', 'frank', 'joe', 'john', 'barry']
list2 = [1, 2, 3, 4]
我想将list1
中的每个名称与list2
中的数字相匹配。由于list2
中有四个数字,我希望将前四个名称中的每一个与list2
中的相应数字配对,并将随机数分配给list1
中的其余名称。< / p>
我知道我可以使用enumerate
和random.choice
的for循环解决此问题。实际上,我已经为原始问题提供了such a solution
我想知道,如果有可能做这样的事情:
for name, number in itertools.izip_longest(list1, list2, fillvalue=MAGIC):
print name, number
最初,我想过使用这样的东西:
MAGIC = random.choice(list1)
但是,首先执行random.choice(list1)
,然后将答案用作压缩操作的fillvalue
。这没有吸引力,因为它没有为它拉链的每对值选择一个新的随机值。因此很明显,itertools.izip_longest
需要fillvalue
,它本身就有一个值,它不会调用它。实际上,如果我要为它提供一个函数,它将产生一个由名称和可调用函数组成的对,它也是低调的。因此,lambda
函数不是可行的解决方案。
如何在调用某个函数时创建调用某个函数的变量? itertools.izip_longest
如何使用fillvalue
变量?是否调用了该变量的__repr__
?如果是这样,我可以创建一个类__repr__
来调用其中的函数吗?
答案 0 :(得分:8)
似乎这里最简单的方法是创建一个生成所有填充值永恒的生成器,然后将其链接到生成list2中的值:
def inf_gen(f):
while True:
yield f()
请注意,inf_gen(f)
实际上等同于iter(f, None)
,因为f
永远不会返回。带有两个参数的iter
调用第一个参数,直到它返回第二个参数。
然后使用它:
>>> from itertools import izip, chain
>>> for name, number in izip(list1,chain(list2, iter(lambda: random.choice(list2), None))):
print name, number
tom 1
mary 2
frank 3
joe 4
john 1
barry 4
您也可以使用itertools来完成此操作,而无需使用itertools.count
生成器理解来定义单独的函数:
>>> from itertools import izip, chain, count
>>> for name, number in izip(list1, chain(list2, (random.choice(list2) for _ in count()))):
print name, number
答案 1 :(得分:3)
如果你想让它“缩放”到多个迭代器,你可以稍微修改http://docs.python.org/2.7/library/itertools.html?highlight=izip_longest#itertools.izip_longest中给出的代码来做到这一点:
from itertools import repeat, chain, count
class ZipExhausted(Exception):
pass
def izip_longest2(*args, **kwds):
fillvalue = kwds.get('fillvalue')
fillgen = kwds.get('fillgen', repeat(fillvalue)) # added
counter = [len(args) - 1]
def sentinel():
if not counter[0]:
raise ZipExhausted
counter[0] -= 1
yield next(fillgen) # modified
iterators = [chain(it, sentinel(), fillgen) for it in args] # modified
try:
while iterators:
yield tuple(map(next, iterators))
except ZipExhausted:
pass
a = ['bob', 'mary', 'paul']
b = ['eggs', 'spam']
c = ['a', 'b', 'c', 'd']
for x in izip_longest2(a, b, c, fillgen=count()):
print '\t'.join(map(str, x))
# output:
# bob eggs a
# mary spam b
# paul 0 c
# 1 2 d