Yes. We can first construct a numpy array that contains L0, L1 and L2:
A = np.array([L0, L1, L2])
Next we construct a numpy array of S:
B = np.array(S)
now we have for C = A[B] (or C = np.take(A,B,axis=0) as suggested by @Divakar):
>>> C = np.take(A,B,axis=0)
>>> C
array([[[[b, 0],
[b, b]],
[[b, b],
[b, 1]],
[[b, b],
[2, b]]],
[[[b, b],
[2, b]],
[[b, 0],
[b, b]],
[[b, b],
[b, 1]]]])
This is of course not exactly what we intended: we want to obtain a 2D-array. We can do this by first transposing (or swapaxes, like @PaulPanzer suggests) and then reshaping, we obtain:
>>> C.transpose(0,2,1,3).reshape(4,6)
array([[b, 0, b, b, b, b],
[b, b, b, 1, 2, b],
[b, b, b, 0, b, b],
[2, b, b, b, b, 1]])
Since 4 and 6 of course depend on the size of the dimensions of L0, L1, L2 and S, we can also calculate them based on that size:
A = np.array([L0, L1, L2])
B = np.array(S)
m, n = B.shape
_, u, v = A.shape
np.take(A,B,axis=0).swapaxes(1,2).reshape(u*m, v*n)
Like @DSM says, from Numpy-1.13, there is np.block function for this purpose, and we can write it as:
>>> np.block([[A[i] for i in row] for row in S])
array([[b, 0, b, b, b, b],
[b, b, b, 1, 2, b],
[b, b, b, 0, b, b],
[2, b, b, b, b, 1]])