Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert None into a list?

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.

like image 602
Calaf Avatar asked Nov 28 '22 23:11

Calaf


2 Answers

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

Update

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?

like image 87
Ashwini Chaudhary Avatar answered Dec 05 '22 03:12

Ashwini Chaudhary


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]
like image 32
mgilson Avatar answered Dec 05 '22 04:12

mgilson