Я ищу способ присоединиться к итераторам python, например itertools.izip_longest()
, но я хотел бы присоединиться к элементам, которые имеют один и тот же «ключ» (как определено параметром) и вывод None
, когда ключ не существует на всех итераторах. Я предполагаю, что итераторы отсортированы по возрастанию на «ключ».Присоединиться к итераторам python по ключу
Пример:
iter1 = iter((1, 3, 4, 9))
iter2 = iter((3, 5, 6))
iter3 = iter((1, 3, 10))
zipjoiner(iter1, iter2, iter3)
должны дать:
iter(((1, None, 1), (3, 3, 3), (4, None, None), (None, 5, None), (None, 6, None), (9, None, None), (None, None, 10)))
(в данном случае ключ является удостоверением по умолчанию lambda x: x
)
Я попытался изменить izip_longest()
реализации, которые содержатся в python documentation и он работает (по крайней мере, на моем примере), но я ищу более элегантное решение. Любая идея?
Это мой код:
def zipjoiner(*args, **kwds):
# izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
key = kwds.get('key', lambda x: x)
counter = [len(args) - 1]
def sentinel():
if not counter[0]:
raise ZipExhausted
counter[0] -= 1
yield fillvalue
fillers = itertools.repeat(fillvalue)
iterators = [itertools.chain(it, sentinel(), fillers) for it in args]
def getkey(x):
return None if x is None else key(x)
try:
while iterators:
elements = tuple(map(next, iterators))
keys = tuple(map(getkey, elements))
minkey = min(_ for _ in keys if not _ is None)
while not all(k == minkey for k in keys):
yield tuple(map(lambda (k, v): v if k == minkey else None, zip(keys, elements)))
elements = tuple(map(lambda (k, it, v): it.next() if k == minkey else v, zip(keys, iterators, elements)))
keys = tuple(map(getkey, elements))
minkey = min(_ for _ in keys if not _ is None)
yield elements
except ZipExhausted:
pass