Создайте итератор, чтобы возвращать элементы из каждого итерируемого по одному - PullRequest
0 голосов
/ 30 января 2019

Я изучал модуль itertools и пытаюсь создать итератор, который будет возвращать каждый элемент из итераций, предоставляемых в качестве входных данных.

Agruments   Results
p, q, …     p0, q0, … plast, qlast 

с еще одним райдером, который, если, скажем, списки не принадлежаттакой же длины, чем next(it) должен возвращать элементы из более длинного списка, когда уходит более короткий.

Попытка решения

import itertools
l1=[1,2,3,4,5,6]
l2=['a','b','c','d']
l=[]
for x,y in itertools.zip_longest(l1,l2):
    l.extend([x,y])
it=iter(x for x in l if x is not None)

Какой тип решает мою проблему

print(list(it))

Выходы:

[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 6]

Есть ли более простой или лучший способ сделать это?Я искал решение для SO и не смог его найти.

Ответы [ 2 ]

0 голосов
/ 30 января 2019

Если вы хотите модифицированную версию своего кода, создайте генератор с самого начала (без списка хранения l):

import itertools
l1=[1,2,3,4,5,6]
l2=['a','b','c','d']

def flat_zip(l1,l2):
    for x,y in itertools.zip_longest(l1,l2):
        if x:
            yield x
        if y:
            yield y
it=flat_zip(l1,l2)

Хотя я советую использовать встроенные решения выше.

0 голосов
/ 30 января 2019

Вы можете использовать itertools.chain.from_iterable(), чтобы сгладить последовательность, и использовать выражение генератора, чтобы отфильтровать значения None:

from itertools import chain, zip_longest

it = (v for v in chain.from_iterable(zip_longest(l1, l2)) if v is not None)

Вместо использования None в качествев качестве значения часового вы можете использовать выделенный страж, чтобы вы могли использовать None в списке ввода:

_sentinel = object()
flattened = chain.from_iterable(zip_longest(l1, l2, fillvalue=_sentinel))
it = (v for v in flattened if v is not _sentinel)

Если вы хотите отфильтровать значения falsey , тогда вы также можете использовать filter(None, ...):

it = filter(None, chain.from_iterable(zip_longest(l1, l2)))

Демо:

>>> from itertools import chain, zip_longest
>>> l1 = [1, 2, 3, 4, 5, 6]
>>> l2 = ['a', 'b', 'c', 'd']
>>> it = (v for v in chain.from_iterable(zip_longest(l1, l2)) if v is not None)
>>> list(it)
[1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 6]

и с местным стражем:

>>> l1 = [1, None, 2, None, 3, None]
>>> l2 = ['a', 'b', 'c', 'd']
>>> _sentinel = object()
>>> flattened = chain.from_iterable(zip_longest(l1, l2, fillvalue=_sentinel))
>>> it = (v for v in flattened if v is not _sentinel)
>>> list(it)
[1, 'a', None, 'b', 2, 'c', None, 'd', 3, None]

itertools раздел рецептов также имеет:

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))
...