Running
L = [1,2,3,4,5,6]
print zip(L,L[1:])[::2]
yields
[(1, 2), (3, 4), (5, 6)]
What zip (or other) statement would yield instead
[1, 2, None, 3, 4, None, 5, 6, None]
?
Update
It's quite all right to start with
L = [(1,2),(3,4),(5,6)]
so long as the statement remains a (fast) one-liner.
Update2
One use case of inserting None is to plot segments quickly.
You can do something like this:
>>> L = [1,2,3,4,5,6]
>>> it = zip(*[iter(L)] * 2)
>>> [y for x in it for y in x + (None,)]
[1, 2, None, 3, 4, None, 5, 6, None]
Performance and space complexity wise @mgilson's approach if modified slightly is the best one of the lot:
>>> from itertools import izip, chain
>>> L = [1,2,3,4,5,6]*10**5
>>> %timeit [y for x in zip(*[iter(L)] * 2) for y in x + (None, )]
10 loops, best of 3: 47.2 ms per loop
If we remove the list-comprehension and use itertools.chain.from_iterable
then you can see there's a significant improvement:
>>> %timeit list(chain.from_iterable(x + (None,) for x in izip(*[iter(L)] * 2)))
10 loops, best of 3: 31.8 ms per loop
>>> %timeit list(insert_none_while(L)) # mgilson's approach
10 loops, best of 3: 50.7 ms per loop
>>> %timeit list(insert_none_for(L))
10 loops, best of 3: 32.6 ms per loop
Here insert_none_while
is @mgilson's original code and insert_none_for
is:
def insert_none_for(iterable):
it = iter(iterable)
for x in it:
yield x
yield next(it)
yield None
A slightly modified version of @Padraic Cunningham's proposed solution seems to be the fastest(only by a slight margin compared to @Jochen Ritzel solution when used with itertools.izip
):
>>> L = [1,2,3,4,5,6]*10**6
>>> %timeit [y for x in zip(*[iter(L)] * 2) for y in x + (None, )]
1 loops, best of 3: 541 ms per loop
>>> %timeit list(chain.from_iterable(x + (None,) for x in izip(*[iter(L)] * 2)))
1 loops, best of 3: 349 ms per loop
# Using while 1 and cached next function
>>> %timeit list(insert_none_while_one(L))
1 loops, best of 3: 470 ms per loop
# Cached next function
>>> %timeit list(insert_none_for(L))
1 loops, best of 3: 351 ms per loop
# Jochen Ritzel's original solutions
>>> %timeit it = iter(L); list(itertools.chain.from_iterable(zip(it, it, repeat(None))))
1 loops, best of 3: 352 ms per loop
# Jochen Ritzel's solutions using izip
>>> %timeit it = iter(L); list(itertools.chain.from_iterable(izip(it, it, repeat(None))))
10 loops, best of 3: 167 ms per loop
# Padraic Cunningham's solution using slicing
>>> %timeit list(chain.from_iterable(izip_longest(L[::2],L[1::2],[None])))
1 loops, best of 3: 236 ms per loop
# Padraic Cunningham's solution using iter
>>> %timeit it=iter(L); list(chain.from_iterable(izip_longest(it, it, [])))
10 loops, best of 3: 156 ms per loop
# Kasra
>>> %timeit list(chain(*[L[i:i+2]+[None] for i in range(0,len(L),2)]))
1 loops, best of 3: 1.43 s per loop
Still not good enough?
Consider using NumPy arrays:
>>> arr = np.array(L, dtype=float)
>>> arr.size
6000000
>>> %timeit np.insert(arr.reshape(-1, 2), 2, None, axis=1).ravel()
10 loops, best of 3: 80.8 ms per loop
Related: How does zip(*[iter(s)]*n)
work in Python?
A simple generator'll do:
>>> def insert_none(iterable):
... itr = iter(iterable)
... while True:
... yield next(itr)
... yield next(itr)
... yield None
...
>>> list(insert_none([1, 2, 3, 4, 5, 6]))
[1, 2, None, 3, 4, None, 5, 6, None]
>>> list(insert_none([1, 2, 3, 4, 5]))
[1, 2, None, 3, 4, None, 5]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With