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.