Mad Physicist
Mad Physicist

Reputation: 114440

Is there a built-in method for checking individual list indices in Python

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

Answers (2)

Mad Physicist
Mad Physicist

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

David Z
David Z

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

Related Questions