Ellipses

Now that we understand how tuple indices work, the remaining basic index types are relatively straightforward. The first type of index we will look at is the ellipsis. An ellipsis is written as literally three dots: ....[1]

Consider an array with three dimensions:

>>> import numpy as np
>>> a = np.arange(24).reshape((3, 2, 4))
>>> a
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23]]])

In one of the examples in the previous section, we wanted to select only the first element of the last axis, and we saw that we could use the index :, :, 0:

>>> a[:, :, 0]
array([[ 0,  4],
       [ 8, 12],
       [16, 20]])

However, this index only works for our specific array, because it has 3 dimensions. If it had 5 dimensions instead, we would need to use a[:, :, :, :, 0]. This is not only tedious to type, but also makes it impossible to write an index that works for any number of dimensions. To contrast, if we want the first element of the first axis, we could write a[0], which works if a has 3 dimensions or 5 dimensions or any number of dimensions.

The ellipsis solves this problem. An ellipsis index skips all the axes of an array to the end, so that the indices after it select the last axes of the array.

>>> a[..., 0]
array([[ 0,  4],
       [ 8, 12],
       [16, 20]])

You can also place indices before the ellipsis. The indices before the ellipsis will select the first axes of the array, and the indices after it will select the last axes. The ellipsis automatically skips all the intermediate axes. For example, to select the first element of the first axis and the last element of the last axis, we could use

>>> a[0, ..., -1]
array([3, 7])

An ellipsis can also skip zero axes if all the axes of the array are already accounted for. For example, these are the same because a has 3 dimensions:

>>> a[1, 0:2, 2]
array([10, 14])
>>> a[1, 0:2, ..., 2]
array([10, 14])

Indeed, the index 1, 0:2, ..., 2 will work with any array that has at least three dimensions (assuming of course that the first dimension is at least size 2 and the last dimension is at least size 3).

Previously, we saw that a tuple index implicitly ends in some number of trivial : slices. We can also see here that a tuple index always implicitly ends with an ellipsis, serving the same purpose. In other words:

An ellipsis automatically serves as a stand-in for the “correct” number of trivial : slices to select the intermediate axes of an array.

And just as with the empty tuple index (), which we saw is the same as writing the right number of trivial : slices, a single ellipsis and nothing else is the same as selecting every axis of the array, i.e., it leaves the array intact.[2]

>>> a[...]
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23]]])

Finally, only one ellipsis is allowed (otherwise it would be ambiguous which axes are being indexed):

>>> a[0, ..., 1, ..., 2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: an index can only have a single ellipsis ('...')

In summary, the rules for an ellipsis index are

  • An ellipsis index is written with three dots: ....

  • ... automatically selects 0 or more intermediate axes in an array.

  • Every index before ... operates on the first axes of the array. Every index after ... operates on the last axes of the array.

  • Every tuple index that does not have an ellipsis in it implicitly ends in ....

  • At most one ... is allowed in a tuple index.

Footnotes