Itertools Chain on Nested List
Question: I have two lists combined sequentially to create a nested list with python's
map and zip funcionality; however, I wish to recreate this with itertools.

Furthermore, I am trying to understand why itertools.chain is returning a
flattened list when I insert two lists, but when I add a nested list it simply
returns the nested list.

Any help on these two issues would be greatly appreciated.

    
    
    from itertools import chain
    
    a = [0,1,2,3]
    b = [4,5,6,7]
    
    #how can I produce this with itertools?
    c = list(map(list, zip(a,b)))
    print(c) #[[0, 4], [1, 5], [2, 6], [3, 7]]
    
    d = list(chain(c))
    print(d) #[[0, 4], [1, 5], [2, 6], [3, 7]]
    
    d = list(chain(a,b))
    print(d) #[0, 1, 2, 3, 4, 5, 6, 7]
    


Answer: I'll try to answer your questions as best I can.

First off, `itertools.chain` doesn't work the way you think it does. `chain`
takes `x` number of iterables and iterates over them in sequence. When you
call `chain`, it essentially (internally) packs the objects into a list:

    
    
    chain("ABC", "DEF") # Internally creates ["ABC", "DEF"]
    

Inside the method, it accesses each of these items one at a time, and iterates
through them:

    
    
    for iter_item in arguments:
        for item in iter_item:
            yield item
    

So when you call `chain([[a,b],[c,d,e],[f,g]])`, it creates a list with _one
iterable object:_ the list you passed as an argument. So now it looks like
this:

    
    
    [ #outer
        [ #inner
            [a,b],
            [c,d,e],
            [f,g]
        ]
    ]
    

`chain` as such iterates over the **inner** list, and returns three elements:
`[a,b]`, `[c,d,e]`, and `[f,g]` in order. Then they get repacked by `list`,
giving you what you had in the first place.

Incidentally, there is a way to do what you want to: `chain.from_iterable`.
This is an alternate constructor for `chain` which accepts a single iterable,
such as your list, and pulls the elements out to iterate over. So instead of
this:

    
    
    # chain(l)
    [ #outer
        [ #inner
            [a,b],
            [c,d,e],
            [f,g]
        ]
    ]
    

You get this:

    
    
    # chain.from_iterable(l)
    [
        [a,b],
        [c,d,e],
        [f,g]
    ]
    

This will iterate through the three sub-lists, and return them in one
sequence, so `list(chain.from_iterable(l))` will return `[a,b,c,d,e,f,g]`.

As for your second question: While I don't know why `itertools` is a necessity
to this process, you can do this in Python 2.x:

`list(itertools.izip(x,y))`

However, in 3.x, the `izip` function has been removed. There is still
`zip_longest`, which will match up as many pairs as it can, and accept a
filler value for extra pairs:
`list(zip_longest([a,b,c],[d,e,f,g,h],fillvalue="N"))` returns
`[(a,d),(b,e),(c,f),(N,g),(N,h)]` since the second list is longer than the
first. Normal `zip` will take the shortest iterable and cut off the rest.

In other words, unless you want `zip_longest` instead of `zip`, `itertools`
does not have a built-in method for zipping.

