pythonmultidimensional-arrayindexingidl

How do I access array elements using int value going from IDL to python?


I am working on code conversion from IDL to python and came across a hurdle. Some code I was given needs to be converted to python. In the IDL version, array element is accessed by int value rather than 3D index. Using the same technique, python gives an error. Any ideas how to resolve this?

Here is a snippet of IDL code for illustration purposes:

x = reform(indgen(100), 2, 5, 10)
help, x ;this results in Array[2,5,10]
x[-76] ; results in value 24

Here is a snippet of python code for illustration purposes

import numpy as np

x=np.arange(100).reshape(2,5,10)
x.shape #this results in (2,5,10)
x[-76]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: index -76 is out of bounds for axis 0 with size 2

Solution

  • NumPy arrays (or anything indexed with integers in Python) doesn't just support that flattened type of indexing. For one, it assumes we know in what order the dimensions are kept in memory, which can be risky.

    However, NumPy does include some functions and methods to help with this:

    import numpy as np
    
    x = np.arange(100).reshape(2, 5, 10)
    
    # to just get the value at that IDL index
    print(x.flat[-76])
    
    
    def idl_idx(xs: np.ndarray, idx: int):
        # unravel_index doesn't support negative indices, so convert them
        if idx < 0:
            idx = xs.size + idx
        return np.unravel_index(idx, xs.shape)
    
    
    # to get the index as a tuple
    print(idl_idx(x, -76))
    
    # to just get that value normally
    print(x[0, 2, 4])
    

    Output:

    24
    (0, 2, 4)
    24
    

    There's no way to change the np.ndarray type itself to support this behaviour, although you could subclass it and add this behaviour. But that would have the limitation of only working for arrays of that type, while some functions (in NumPy and elsewhere) may return new arrays of type np.ndarray that would no longer work like that - that may be something you want to avoid.