代码之家  ›  专栏  ›  技术社区  ›  Bitto

创建迭代器以逐个返回每个iterable中的元素

  •  6
  • Bitto  · 技术社区  · 6 年前

    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 回复  |  直到 6 年前
        1
  •  9
  •   Martijn Pieters    6 年前

    你可以用 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)
    

    而不是使用 作为sentinel值,您可能需要使用专用的sentinel,以便可以使用 没有一个 在输入列表中:

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

    falsey values 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 recipes section 还有:

    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))
    
        2
  •  2
  •   Learning is a mess    6 年前

    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)
    

    尽管我建议使用上面的内置解决方案。

        3
  •  0
  •   Subham    4 年前

    仅使用列表理解。 评论中的解释。 仅为变更添加。

    A = [1, 2, 3, 4, 5, 6]
    B = ["A", "B", "C"]
    
    # zipping equal length 
    flattened_zip_list = [item for sublist in zip(A, B) for item in sublist]
    
    print(flattened_zip_list )
    
    # leftover from longest list 
    extra_list = [A[index] for index in range(min(len(A), len(B)), max(len(A), len(B)) if len(A) > len(B) else B[index])]
    
    print(extra_list)
    
    # final list 
    flattened_zip_list.extend(extra_list)
    
    print(flattened_zip_list)
    

    输出

    [1, 'A', 2, 'B', 3, 'C'] # after zipping same lengths 
    [4, 5, 6] # leftover values 
    [1, 'A', 2, 'B', 3, 'C', 4, 5, 6] # [1, 'a', 2, 'b', 3, 'c', 4, 'd', 5, 6], the one mentioned in question 
    
    [Program finished]