Is it possible to use the same slice notation in both a list and an element to get the same result?

Question:

I want to get the element in the last index of a list, but sometimes the last index is a list, in this case I want the first element in the nested list.

#list in moment 1:
Lm1 = [1,2,3,4]

#list in moment 2:
Lm2 = [1,2,3,4,[1,2,3]]

I can just use an if for this.

#Option1:

def if_list(lastposition):
    if isinstance(lastposition, list):
        return list[0]
    else:
        return lastposition

element = if_list(Lm1[-1])
do whatever

Or if I want to do the same operation in both cases I could buit the list like this and use the same slice notation. It will give the element I want.

#Option2:

Lm1 = [[1],[2],[3],[4]]
Lm2 = [[1],[2],[3],[4],[1,2,3]]

Lm1[-1][0]
Lm2[-1][0]

Is there a way to do this using something similar to slice notation that will work in both cases (when index is list and when index is not list) or a simple one liner?

Something like:

#Lm1[-1:][:]...

The problem is that I don’t know if its more time eficient to just build the list
like Option2 and use the same slice notation or to use the if cause everytime like Option1.

I’m using pythom 3.7, don’t know much about older versions.

Asked By: Thiago Luiz

||

Answers:

I created a test bench to compare using try-except and isinstance to see which is faster and here are the results.

Option2:
Parsing all data to a list doesn’t seem like an efficient way to me. :/

import time, statistics 

Lm2 = [1,2,3,4,1,2,3]
t = []
for y in range(4):
    s = time.time()
    for i in range(100000):
        if isinstance(Lm2[-1], list):
            x =  Lm2[-1][0]
        else:
            x = Lm2[-1]
    t.append(time.time() - s)
print(statistics.mean(t))

Lm2 = [1,2,3,[4,1,2,3]]
t = []
for y in range(4):
    s = time.time()
    for i in range(100000):
        try:
            x =  Lm2[-1][0]
        except Exception:
            x = Lm2[-1]
    t.append(time.time() - s)
print(statistics.mean(t))

Lm2 = [1,2,3,[4,1,2,3]]
t = []
for y in range(4):
    s = time.time()
    for i in range(100000):
        x = Lm2[-1][0] if type(Lm2[-1]) is list else Lm2[-1]
    t.append(time.time() - s)
print(statistics.mean(t))

The results as follow in order

# When the last element is a list 
# 0.024208366870880127
# 0.011709034442901611
# 0.03266298770904541

# When the last element is an int 
# 0.02896404266357422
# 0.015629112720489502
# 0.03452497720718384

According to the data I got, using try-except will be always faster

Answered By: Marsilinou Zaky

You can do a one liner like this if you want:

#list in moment 1:
Lm1 = [1,2,3,4]

#list in moment 2:
Lm2 = [1,2,3,4,[1,2,3]]

def test(test_list):
    return test_list[-1][0] if type(test_list[-1]) is list else test_list[-1]

print(test(Lm1))
print(test(Lm2))

Check if the last value is a list, if it is, return the first value, otherwise give you the last element of your list.

Answered By: Simon

Yes you can achieve desired behavior by not just creating two options.
Here is the code works for both options:

    def get_last_element(lst):
        last = lst[-1]
        return last[0] if isinstance(last, list) else last

    # Example usage
    Lm1 = [1, 2, 3, 4]
    Lm2 = [1, 2, 3, 4, [1, 2, 3]]

    element1 = get_last_element(Lm1)
    element2 = get_last_element(Lm2)

    print(element1)  # Output: 4
    print(element2)  # Output: 1

The function get_last_element() checks lst’s last element is a list. If it is it returns first element using indexing last[0], otherwise the last element of the list.

Answered By: Sunnat Amirov