Search code examples
pythonlisttuplesindices

Using variable tuple to access elements of list


Disclaimer:beginner, self-teaching Python user.

A pretty cool feature of ndarrays is their ability to accept a tuple of integers as indices (e.g. myNDArray[(1,2)] == myNDArray[1][2]). This allows me to leave the indices unspecified as a variable (e.g. indicesTuple ) until a script determines what part of an ndarray to work with, in which case the variable is specified as a tuple of integers and used to access part of an ndarray (e.g. myNDArray[indicesTuple]). The utility in using a variable is that the LENGTH of the tuple can be varied depending on the dimensions of the ndarray.

However, this limits me to working with arrays of numerical values. I tried using lists, but they can't take in a tuple as indices (e.g. myList[(1,2)] gives an error.). Is there a way to "unwrap" a tuple for list indices as one could for function arguments? Or something far easier or more efficient?

UPDATE: Holy shite I forgot this existed. Basically I eventually learned that you can initialize the ndarray with the argument dtype=object, which allows the ndarray to contain multiple types of Python objects, much like a list. As for accessing a list, as a commenter pointed out, I could use a for-loop to iterate through the variable indicesTuple to access increasingly nested elements of the list. For in-place editing, see the accepted comment, really went the extra mile there.


Solution

  • I'm interpreting your question as:

    I have an N-dimensional list, and a tuple containing N values (T1, T2... TN). How can I use the tuple values to access the list? I don't know what N will be ahead of time.

    I don't know of a built-in way to do this, but you can write a method that iteratively digs into the list until you reach the innermost value.

    def get(seq, indices):
        for index in indices:
            seq = seq[index]
        return seq
    
    seq = [
        [
            ["a","b"],
            ["c","d"]
        ],
        [
            ["e","f"],
            ["g","h"]
        ]
    ]
    
    indices = [0,1,0]
    print get(seq, indices)
    

    Result:

    c
    

    You could also do this in one* line with reduce, although it won't be very clear to the reader what you're trying to accomplish.

    print reduce(lambda s, idx: s[idx], indices, seq)
    

    (*if you're using 3.X, you'll need to import reduce from functools. So, two lines.)


    If you want to set values in the N-dimensional list, use get to access the second-deepest level of the list, and assign to that.

    def set(seq, indices, value):
        innermost_list = get(seq, indices[:-1])
        innermost_list[indices[-1]] = value