Itertools Chain on Nested List
<p>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. </p>

<p>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. </p>

<p>Any help on these two issues would be greatly appreciated. </p>

<pre><code>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]
</code></pre>

<p>I'll try to answer your questions as best I can.</p>

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

<pre><code>chain("ABC", "DEF") # Internally creates ["ABC", "DEF"]
</code></pre>

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

<pre><code>for iter_item in arguments:
    for item in iter_item:
        yield item
</code></pre>

<p>So when you call <code>chain([[a,b],[c,d,e],[f,g]])</code>, it creates a list with <em>one iterable object:</em> the list you passed as an argument. So now it looks like this:</p>

<pre><code>[ #outer
    [ #inner
        [a,b],
        [c,d,e],
        [f,g]
    ]
]
</code></pre>

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

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

<pre><code># chain(l)
[ #outer
    [ #inner
        [a,b],
        [c,d,e],
        [f,g]
    ]
]
</code></pre>

<p>You get this:</p>

<pre><code># chain.from_iterable(l)
[
    [a,b],
    [c,d,e],
    [f,g]
]
</code></pre>

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

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

<p><code>list(itertools.izip(x,y))</code></p>

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

<p>In other words, unless you want <code>zip_longest</code> instead of <code>zip</code>, <code>itertools</code> does not have a built-in method for zipping.</p>

python python-3.x