The itertools.islice
function can produce a slice from any iterable. The statement:
itertools.islice(lst, 0, None, 2)
In simplified terms means "return an iterator which, when evaluated, will return every other element in lst starting with the element at 0". The 0
arg is the starting point and 2
is the step value (how many to skip to get the next value)
It would be better to use a 6-element list to illustrate, since looking at [(1, 2), (1, 5)]
it may be unclear which function produces the inner tuples (they are not produced until the final izip).
>>> lst = [1, 2, 3, 4, 5, 6]
>>> list(itertools.islice(lst, 0, None, 2))
[1, 3, 5]
>>> list(itertools.islice(lst, 0, None, 2))
[2, 4, 6]
Be careful using this with a generator; the first call will traverse the whole sequence, draining the generator:
>>> def foo():
... for i in range(6):
... yield i + 1
>>>
>>> gen = foo()
>>> list(itertools.islice(gen, 0, None, 2)
[1, 3, 5]
>>> list(itertools.islice(gen, 1, None, 2)
[]
Your function needs to produce 2 sequences, odds and evens. This is where the list comprehension comes in:
>>> [itertools.islice(lst, i, None, 2) for i in range(2)]
[<itertools.islice object at 0x7f958a79eaf8>, <itertools.islice object at 0x7f958a79eaa0>]
Now you have 2 islice objects ready to be interleaved. To do this we could use zip
, but itertools.izip
is more efficient because it returns an iterator:
>>> list(zip([1, 3, 5], [2, 4, 6]))
[(1, 2), (3, 4), (5, 6)]
>>> tmp = itertools.izip(*[itertools.islice(lst, i, None, 2) for i in range(2)])
>>> tmp
<itertools.izip object at 0x7f958a7b6cf8>
>>> list(tmp)
[(1, 2), (3, 4), (5, 6)]
Hope that helps clarify the steps.