What is the difference between chain and chain.from_iterable in itertools?

前端 未结 6 1317
庸人自扰
庸人自扰 2020-12-07 20:05

I could not find any valid example on the internet where I can see the difference between them and why to choose one over the other.

6条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-12-07 20:37

    I could not find any valid example ... where I can see the difference between them [chain and chain.from_iterable] and why to choose one over the other

    The accepted answer is thorough. For those seeking a quick application, consider flattening several lists:

    list(itertools.chain(["a", "b", "c"], ["d", "e"], ["f"]))
    # ['a', 'b', 'c', 'd', 'e', 'f']
    

    You may wish to reuse these lists later, so you make an iterable of lists:

    iterable = (["a", "b", "c"], ["d", "e"], ["f"])
    

    Attempt

    However, passing in an iterable to chain gives an unflattened result:

    list(itertools.chain(iterable))
    # [['a', 'b', 'c'], ['d', 'e'], ['f']]
    

    Why? You passed in one item (a tuple). chain needs each list separately.


    Solutions

    When possible, you can unpack an iterable:

    list(itertools.chain(*iterable))
    # ['a', 'b', 'c', 'd', 'e', 'f']
    
    list(itertools.chain(*iter(iterable)))
    # ['a', 'b', 'c', 'd', 'e', 'f']
    

    More generally, use .from_iterable (as it also works with infinite iterators):

    list(itertools.chain.from_iterable(iterable))
    # ['a', 'b', 'c', 'd', 'e', 'f']
    
    g = itertools.chain.from_iterable(itertools.cycle(iterable))
    next(g)
    # "a"
    

提交回复
热议问题