D R
D R

Reputation: 22492

Interleaving two NumPy arrays efficiently

Assume the following arrays are given:

a = array([1, 3, 5])
b = array([2, 4, 6])

How would one interleave them efficiently so that one gets a third array like the following?

c = array([1, 2, 3, 4, 5, 6])

It can be assumed that length(a) == length(b).

Upvotes: 120

Views: 61091

Answers (14)

K. W. Cooper
K. W. Cooper

Reputation: 333

Not the prettiest function, but I needed one that could interleave an arbitrary number of matrices. Maybe helpful?

 def interleave_narr(*args):
        ''' Given N numpy arrays, interleave arr i+1...i+N'''
        m_sizes = 0
        for m in args:
                m_sizes += m.size
        o = np.empty((m_sizes,), dtype=args[0].dtype)
    
        n_mats = len(args)
        for ii in range(n_mats):
            o[ii::n_mats] = args[ii]
        return o

Upvotes: 0

Muhammad Yasirroni
Muhammad Yasirroni

Reputation: 2137

For 2D numpy array:

def interleave2d(a, b):
    """Interleave between columns of two arrays"""
    c = np.empty((len(a), a.shape[1] * 2), dtype=a.dtype)
    c[:, 0::2] = a
    c[:, 1::2] = b
    return c

Upvotes: 0

bhanukiran
bhanukiran

Reputation: 164

vstack sure is an option, but a more straightforward solution for your case could be the hstack:

a = array([1,3,5])
b = array([2,4,6])
hstack((a,b)) # Remember it is a tuple of arrays that this function swallows in.
array([1, 3, 5, 2, 4, 6])
sort(hstack((a,b)))
array([1, 2, 3, 4, 5, 6])

And more importantly this works for arbitrary shapes of a and b.

Also you may want to try out dstack:

a = array([1,3,5])
b = array([2,4,6])
dstack((a,b)).flatten()
array([1, 2, 3, 4, 5, 6])

You’ve got options now!

Upvotes: 2

MSeifert
MSeifert

Reputation: 152587

I thought it might be worthwhile to check how the solutions performed in terms of performance. And this is the result:

enter image description here

This clearly shows that the most upvoted and accepted answer (Paul's answer) is also the fastest option.

The code was taken from the other answers and from another Q&A:

# Setup
import numpy as np

def Paul(a, b):
    c = np.empty((a.size + b.size,), dtype=a.dtype)
    c[0::2] = a
    c[1::2] = b
    return c

def JoshAdel(a, b):
    return np.vstack((a,b)).reshape((-1,),order='F')

def xioxox(a, b):
    return np.ravel(np.column_stack((a,b)))

def Benjamin(a, b):
    return np.vstack((a,b)).ravel([-1])

def andersonvom(a, b):
    return np.hstack(zip(a,b))

def bhanukiran(a, b):
    return np.dstack((a,b)).flatten()

def Tai(a, b):
    return np.insert(b, obj=range(a.shape[0]), values=a)

def Will(a, b):
    return np.ravel((a,b), order='F')

# Timing setup
timings = {Paul: [], JoshAdel: [], xioxox: [], Benjamin: [], andersonvom: [], bhanukiran: [], Tai: [], Will: []}
sizes = [2**i for i in range(1, 20, 2)]

# Timing
for size in sizes:
    func_input1 = np.random.random(size=size)
    func_input2 = np.random.random(size=size)
    for func in timings:
        res = %timeit -o func(func_input1, func_input2)
        timings[func].append(res)

%matplotlib notebook

import matplotlib.pyplot as plt
import numpy as np

fig = plt.figure(1)
ax = plt.subplot(111)

for func in timings:
    ax.plot(sizes,
            [time.best for time in timings[func]],
            label=func.__name__)  # you could also use "func.__name__" here instead
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel('size')
ax.set_ylabel('time [seconds]')
ax.grid(which='both')
ax.legend()
plt.tight_layout()

Just in case you have numba available you could also use that to create a function:

import numba as nb

@nb.njit
def numba_interweave(arr1, arr2):
    res = np.empty(arr1.size + arr2.size, dtype=arr1.dtype)
    for idx, (item1, item2) in enumerate(zip(arr1, arr2)):
        res[idx*2] = item1
        res[idx*2+1] = item2
    return res

It could be slightly faster than the other alternatives:

Enter image description here

Upvotes: 115

Tai
Tai

Reputation: 7984

One can also try np.insert (the solution was migrated from Interleave NumPy arrays).

import numpy as np

a = np.array([1,3,5])
b = np.array([2,4,6])
np.insert(b, obj=range(a.shape[0]), values=a)

Please see the documentation and tutorial for more information.

Upvotes: 2

Will
Will

Reputation: 163

Improving xioxox's answer:

import numpy as np

a = np.array([1,3,5])
b = np.array([2,4,6])
inter = np.ravel((a,b), order='F')

Upvotes: 8

Benjamin
Benjamin

Reputation: 11860

Maybe this is more readable than JoshAdel's solution:

c = numpy.vstack((a,b)).ravel([-1])

Upvotes: 4

Paul
Paul

Reputation: 43620

I like Josh's answer. I just wanted to add a more mundane, usual, and slightly more verbose solution. I don't know which is more efficient. I expect they will have similar performance.

import numpy as np

a = np.array([1,3,5])
b = np.array([2,4,6])

c = np.empty((a.size + b.size,), dtype=a.dtype)
c[0::2] = a
c[1::2] = b

Upvotes: 205

Zhaosheng Pan
Zhaosheng Pan

Reputation: 11

Another one-liner:

>>> c = np.array([a, b]).T.flatten()
>>> c
array([1, 2, 3, 4, 5, 6])

Upvotes: 1

Arty
Arty

Reputation: 16737

Another one-liner: np.vstack((a,b)).T.ravel()
One more: np.stack((a,b),1).ravel()

Upvotes: 2

clwainwright
clwainwright

Reputation: 1704

I needed to do this but with multidimensional arrays along any axis. Here's a quick general purpose function to that effect. It has the same call signature as np.concatenate, except that all input arrays must have exactly the same shape.

import numpy as np

def interleave(arrays, axis=0, out=None):
    shape = list(np.asanyarray(arrays[0]).shape)
    if axis < 0:
        axis += len(shape)
    assert 0 <= axis < len(shape), "'axis' is out of bounds"
    if out is not None:
        out = out.reshape(shape[:axis+1] + [len(arrays)] + shape[axis+1:])
    shape[axis] = -1
    return np.stack(arrays, axis=axis+1, out=out).reshape(shape)

Upvotes: 5

xioxox
xioxox

Reputation: 2670

Here is a simpler answer than some of the previous ones

import numpy as np
a = np.array([1,3,5])
b = np.array([2,4,6])
inter = np.ravel(np.column_stack((a,b)))

After this inter contains:

array([1, 2, 3, 4, 5, 6])

This answer also appears to be marginally faster:

In [4]: %timeit np.ravel(np.column_stack((a,b)))
100000 loops, best of 3: 6.31 µs per loop

In [8]: %timeit np.ravel(np.dstack((a,b)))
100000 loops, best of 3: 7.14 µs per loop

In [11]: %timeit np.vstack((a,b)).ravel([-1])
100000 loops, best of 3: 7.08 µs per loop

Upvotes: 26

andersonvom
andersonvom

Reputation: 11851

This will interleave/interlace the two arrays and I believe it is quite readable:

a = np.array([1,3,5])      #=> array([1, 3, 5])
b = np.array([2,4,6])      #=> array([2, 4, 6])
c = np.hstack( zip(a,b) )  #=> array([1, 2, 3, 4, 5, 6])

Upvotes: 10

JoshAdel
JoshAdel

Reputation: 68682

Here is a one-liner:

c = numpy.vstack((a,b)).reshape((-1,),order='F')

Upvotes: 49

Related Questions