Reputation: 114440
Python has a built in functionality for checking the validity of entire slices: slice.indices
. Is there something similar that is built-in for individual indices?
Specifically, I have an index, say a = -2
that I wish to normalize with respect to a 4-element list. Is there a method that is equivalent to the following already built in?
def check_index(index, length):
if index < 0:
index += length
if index < 0 or index >= length:
raise IndexError(...)
My end result is to be able to construct a tuple with a single non-None
element. I am currently using list.__getitem__
to do the check for me, but it seems a little awkward/overkill:
items = [None] * 4
items[a] = 'item'
items = tuple(items)
I would like to be able to do
a = check_index(a, 4)
items = tuple('item' if i == a else None for i in range(4))
Everything in this example is pretty negotiable. The only things that are fixed is that I am getting a
in a way that can have all of the problems that an arbitrary index can have and that the final result has to be a tuple
.
I would be more than happy if the solution used numpy and only really applied to numpy arrays instead of Python sequences. Either one would be perfect for the application I have in mind.
Upvotes: 2
Views: 588
Reputation: 114440
There is a function called numpy.core.multiarray.normalize_axis_index
which does exactly what I need. It is particularly useful to be because the implementation I had in mind was for numpy
array indexing:
from numpy.core.multiarray import normalize_axis_index
>>> normalize_axis_index(3, 4)
3
>>> normalize_axis_index(-3, 4)
1
>>> normalize_axis_index(-5, 4)
...
numpy.core._internal.AxisError: axis -5 is out of bounds for array of dimension 4
The function was added in version 1.13.0. The source for this function is available here, and the documentation source is here.
Upvotes: 2
Reputation: 131640
If I understand correctly, you can use range(length)[index]
, in your example range(4)[-2]
. This properly handles negative and out-of-bounds indices. At least in recent versions of Python, range()
doesn't literally create a full list so this will have decent performance even for large arguments.
If you have a large number of indices to do this with in parallel, you might get better performance doing the calculation with Numpy vectorized arithmetic, but I don't think the technique with range
will work in that case. You'd have to manually do the calculation using the implementation in your question.
Upvotes: 2