简体   繁体   中英

Insert items from list to another list every n positions

I have the following list.

vector = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
inserted_elements = [2, 2, 2, 2, 2]

I want to get the following by inserting every two elements.

output = [1, 2, 2, 3, 4, 2, 5, 6, 2, 7, 8, 2, 9, 10, 2]

Not only the Python list but also the answer using numpy array is fine.

I don't think there's an easy NumPy way to do this for any possible size of arrays, but here's a python way of doing so using iterators and list comprehension:

it1, it2 = map(iter, (vector, inserted_elements))
n = sum(map(len, (vector, inserted_elements)))

[next(it2) if i % 3 == 0 else next(it1) for i in range(1, n+1)]
# [1, 2, 2, 3, 4, 2, 5, 6, 2, 7, 8, 2, 9, 10, 2]

Every 3 rd element in the output will come from it2 , the iterator for inserted_elements . The rest come from it1 which corresponds to vector .

numpy array step:

1.

>>> a=np.reshape(np.matrix([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),(5, 2))
>>> a
matrix([[ 1,  2],
        [ 3,  4],
        [ 5,  6],
        [ 7,  8],
        [ 9, 10]])

2.

>>> b=np.reshape(np.matrix([2, 2, 2, 2, 2]),(5, 1))
>>> b
matrix([[2],
        [2],
        [2],
        [2],
        [2]])

3.

>>> M = np.append(a, b, axis=1)
>>> M
matrix([[ 1,  2,  2],
        [ 3,  4,  2],
        [ 5,  6,  2],
        [ 7,  8,  2],
        [ 9, 10,  2]])

4.

>>> result=np.array(M).flatten()
>>> result
array([ 1,  2,  2,  3,  4,  2,  5,  6,  2,  7,  8,  2,  9, 10,  2])

A traditional for-loop approach might look like as follows, where you pick 2 elements from vector and 1 element from inserted_elements and make the output list

vector = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
inserted_elements = [2, 2, 2, 2, 2]

output = []

#Pick two elements from vector and one element from inserted_elements and add it to output list
for idx in range(0,len(vector),2):

    output.extend(vector[idx:idx+2] + [inserted_elements[int(idx/2)]])

print(output)

The same thing in list-comprehension will be

output = [ v for idx in range(0,len(vector),2) for v in vector[idx:idx+2] + [inserted_elements[int(idx/2)]]]

The output will be

[1, 2, 2, 3, 4, 2, 5, 6, 2, 7, 8, 2, 9, 10, 2]

Here's a somewhat obscure approach - but it's faster than anything else (so far):

list(itertools.chain(*zip(*[iter(vector)]*2+[iter(inserted_elements)]))) 

It uses a 'idiom' for taking items in size n groups, [iter(alist)]*n , and itertools.chain as a way of flattening a nested list.

A deleted answer used np.insert . For this I believe insert uses masking as demonstrated below:

def foo(vector, inserted_elements):
    res = np.zeros(len(vector)+len(inserted_elements),int)  
    mask = res.astype(bool) 
    mask[2::3]=True 
    res[mask]=inserted_elements 
    res[~mask]=vector    
    return res

A variation on the np.append answer is:

np.column_stack((np.reshape(vector,(-1,2)), inserted_elements)).ravel()

I generally don't like np.append , since it is often misused, especially in loops. For this it's ok, but I think column_stack is cleaner.

===

In [254]: list(zip(*[iter(vector)]*2+[iter(inserted_elements)]))                                         
Out[254]: [(1, 2, 2), (3, 4, 2), (5, 6, 2), (7, 8, 2), (9, 10, 2)]

Here's an itertools based approach, which also works for an arbitrary number of elements to be inserted from one list to the other. For this I've defined a generator function, which will insert and element from l2 into l1 every i items:

def insert_every_n(l1, l2, k):
    i1, i2 = iter(l1), iter(l2)
    while True:
        try:
            yield from islice(i1, k)
            yield next(i2)
        except StopIteration:
            return

This works by yielding up to i items from the iterator l1 on each iteration by using itertools.islice . With yield from we are yielding as many items as there are in the sliced iterable, so the iterable is run to exhaustion, (a shortcut for for v in g: yield v ).

Finally we can wrap the yield statements with a try / expect to catch the StopIteration warning.


Let's try with the proposed example:

vector = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
inserted_elements = [2, 2, 2, 2, 2]

list(insert_every_n(vector, inserted_elements, k=2))
# [1, 2, 2, 3, 4, 2, 5, 6, 2, 7, 8, 2, 9, 10, 2]

And if we wanted to add an item of l2 every 3 items:

vector = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
inserted_elements = [2, 2, 2, 2]

list(insert_every_n(vector, inserted_elements, k=3))
# [1, 2, 3, 2, 4, 5, 6, 2, 7, 8, 9, 2, 10, 2]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM