Your example can be rewritten as a list comprehension:
In [121]: [c[idx] for idx in indices]
Out[121]:
[array([4, 2, 1, 2]),
array([3, 2, 2, 3]),
array([3, 2, 2, 3]),
array([0, 3, 4, 4])]
which can be turned into a nice 2d array:
In [122]: np.array([c[idx] for idx in indices])
Out[122]:
array([[4, 2, 1, 2],
[3, 2, 2, 3],
[3, 2, 2, 3],
[0, 3, 4, 4]])
Here np.array()
is a form of concatenation, joining the arrays along a new axis.
Since the 2nd index is the same for all rows (slice(4)
), this indexing also works:
In [123]: c[[0,1,1,2],slice(4)] # or [...,:4]
Out[123]:
array([[4, 2, 1, 2],
[3, 2, 2, 3],
[3, 2, 2, 3],
[0, 3, 4, 4]])
Repetition on the 1st axis is not a problem. Differing slices in the 2nd take some more manipulation. Except for this special :4
case, you will have to turn the slices in to ranges. There's no way of indexing one dimension with multiple slices.
The case where the slices all have same length, but different 'start' values, is similar to the one discussed in https://stackoverflow.com/a/28007256/901925 access-multiple-elements-of-an-array
.
In [135]: c.flat[[i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices]]
Out[135]:
array([[4, 2, 1, 2],
[3, 2, 2, 3],
[3, 2, 2, 3],
[0, 3, 4, 4]])
The indices that I generate this way are:
In [136]: [i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices]
Out[136]:
[array([0, 1, 2, 3]),
array([5, 6, 7, 8]),
array([5, 6, 7, 8]),
array([10, 11, 12, 13])]
It works fine if indices
is somewhat irregular: indices1 = [[0, slice(0, 3)], [1, slice(2, 5)], [1, slice(1, 4)], [2, slice(0, 3)]]
My earlier answer looks at some other ways indexing. But often indexing on a flatten array is fastest, even if you take into account the calculation required to generate the index array.
If the slices vary in length, then you are stuck with generating a list of arrays, or an hstack
of such a list:
In [158]: indices2 = [[0, slice(0, 2)], [1, slice(2, 5)],
[1, slice(0, 4)], [2, slice(0, 5)]]
In [159]: c.flat[np.hstack([i*c.shape[1]+np.arange(j.start,j.stop)
for i,j in indices2])]
Out[159]: array([4, 2, 2, 3, 1, 3, 2, 2, 3, 0, 3, 4, 4, 3])
In [160]: [c.flat[i*c.shape[1]+np.arange(j.start,j.stop)] for i,j in indices2]
Out[160]: [array([4, 2]), array([2, 3, 1]), array([3, 2, 2, 3]),
array([0, 3, 4, 4, 3])]
In [161]: np.hstack(_)
Out[161]: array([4, 2, 2, 3, 1, 3, 2, 2, 3, 0, 3, 4, 4, 3])
more on the varying, but equal length slices:
In [190]: indices1 = [[0, slice(0, 3)], [1, slice(2, 5)], [1, slice(1, 4)], [2, slice(0, 3)]]
In [191]: c.flat[[i*c.shape[1]+np.arange(j.start,j.stop) for i,j in indices1]]Out[191]:
array([[4, 2, 1],
[2, 3, 1],
[2, 2, 3],
[0, 3, 4]])
In [193]: rows = [[i] for i,j in indices1]
In [200]: cols=[np.arange(j.start,j.stop) for i,j in indices1]
In [201]: c[rows,cols]
Out[201]:
array([[4, 2, 1],
[2, 3, 1],
[2, 2, 3],
[0, 3, 4]])
In this case rows
is a vertical list that can be broadcasted with cols
.