88

Is there clean way to get the value at a list index or None if the index is out or range in Python?

The obvious way to do it would be this:

if len(the_list) > i:
 return the_list[i]
else:
 return None

However, the verbosity reduces code readability. Is there a clean, simple, one-liner that can be used instead?

asked Aug 29, 2012 at 20:56
2

9 Answers 9

91

Try:

try:
 return the_list[i]
except IndexError:
 return None

Or, one liner:

l[i] if i < len(l) else None

Example:

>>> l=list(range(5))
>>> i=6
>>> print(l[i] if i < len(l) else None)
None
>>> i=2
>>> print(l[i] if i < len(l) else None)
2
Thom Wiggers
7,0722 gold badges41 silver badges66 bronze badges
answered Aug 29, 2012 at 20:59

8 Comments

This has the unfortunate side-effect of using exceptions as control flow, which his original already doesn't and this isn't much less verbose.
@DanielDiPaolo: In python, using exceptions this way is encouraged and not frowned upon.
@BrtH: well theres two schools of thought on that the LBYL (Look before you leap (if statements)) crowd and the EAFP (easier to ask forgiveness then permission (try/excepts)) crowd... but yeah in general using exceptions this way is definitely not frowned upon ... but i think it largely comes down to personal preference
I doubt exception flow will be as performant as a simple if-else.
Except that in Python exception flow is more performant: Exceptions are very light in Python, and only incur their (limited) overhead when an exception occurs. An if statement means a comparison is ran when the code would have executed anyway. Check this answer and this doc
|
57

I find list slices good for this:

>>> x = [1, 2, 3]
>>> a = x [1:2]
>>> a
[2]
>>> b = x [4:5]
>>> b
[]

So, always access x[i:i+1], if you want x[i]. You'll get a list with the required element if it exists. Otherwise, you get an empty list.

answered Jan 22, 2016 at 6:18

6 Comments

Addendum: This can be expanded to be my_list[idx: idx+1] or "Default_value". Readable and succinct! :)
This should be the accepted answer as a one-liner that avoids an if and works with empty lists. It works well with lists created by list comprehension as well: a = [1,3,5,7,9]; b = [num for num in a if num % 2 == 0][0:1] or "No evens found"; print(b) No evens found
@Erich Nice but it results in a list, instead of a value. So full one liner will look ugly: (my_list[idx: idx+1] or ["Default_value"])[0]
@SergeyNudnov I agree with your solution. It's a bit hairy but the cleanest way to do it as a one-liner. I would say that at this point it might warrant a small helper function in a personal lib
You can make this much shorter using unpacking assignment. Given the list splice x[1:2], you could assign it to var via many forms of unpacking. Tuple unpacking: (var,) = x[1:2] or var, = x[1:2] or var, *_ = x[1:2]. List unpacking: [var] = x[1:2]. Whilst I normally don't use brackets for tuple unpacking, in this case I'd prefer (var,) = x[1:2] as it's both short and (IMHO) explicit, since the tuple form should be more recognisable.
|
16

If you are dealing with small lists, you do not need to add an if statement or something of the sorts. An easy solution is to transform the list into a dict. Then you can use dict.get:

table = dict(enumerate(the_list))
return table.get(i)

You can even set another default value than None, using the second argument to dict.get. For example, use table.get(i, 'unknown') to return 'unknown' if the index is out of range.

Note that this method does not work with negative indices.

answered Apr 11, 2018 at 11:43

Comments

11

For your purposes you can exclude the else part as None is return by default if a given condition is not met.

def return_ele(x, i):
 if len(x) > i: return x[i]

Result

>>> x = [2,3,4]
>>> b = return_ele(x, 2)
>>> b
4
>>> b = return_ele(x, 5)
>>> b
>>> type(b)
<type 'NoneType'>
answered Aug 29, 2012 at 21:07

Comments

11

Combining slicing and iterating

next(iter(the_list[i:i+1]), None)
answered Jan 10, 2020 at 10:21

3 Comments

Note to readers: The only way I can interpret this answer is that it is a joke. You should never use this as a solution to the problem in OP's question.
@MichaelGeary: I don't see why you think this is a joke. At the time of writing this is the only answer, which does not refer to the list twice, which is very handy when your list is a temporary object. Aside from that you are able choose the alternative return value all in one statement.
I like this because of it's one liner aspect but it seems it is actually the least performant. Check out @XerCis's answer with benchmarks.
10

1. if...else...

l = [1, 2, 3, 4, 5]
for i, current in enumerate(l):
 following = l[i + 1] if i + 1 < len(l) else None
 print(current, following)
# 1 2
# 2 3
# 3 4
# 4 5
# 5 None

2. try...except...

l = [1, 2, 3, 4, 5]
for i, current in enumerate(l):
 try:
 following = l[i + 1]
 except IndexError:
 following = None
 print(current, following)
# 1 2
# 2 3
# 3 4
# 4 5
# 5 None

3. dict

suitable for small list

l = [1, 2, 3, 4, 5]
dl = dict(enumerate(l))
for i, current in enumerate(l):
 following = dl.get(i + 1)
 print(current, following)
# 1 2
# 2 3
# 3 4
# 4 5
# 5 None

4. List slicing

l = [1, 2, 3, 4, 5]
for i, current in enumerate(l):
 following = next(iter(l[i + 1:i + 2]), None)
 print(current, following)
# 1 2
# 2 3
# 3 4
# 4 5
# 5 None

5. itertools.zip_longest

from itertools import zip_longest
l = [1, 2, 3, 4, 5]
for i, (current, following) in enumerate(zip_longest(l, l[1:])):
 print(current, following)
# 1 2
# 2 3
# 3 4
# 4 5
# 5 None

Using Jupyter magic command of %%timeit

init

from itertools import zip_longest
l = list(range(10000000))

Result

Method Consume
if...else... 2.62 s
try...except... 1.14 s
dict 2.61 s
List slicing 3.75 s
itertools.zip_longest 1.14 s
answered Jun 24, 2021 at 8:44

1 Comment

Thank you for presenting several scenarios + benchmarking them. A very insightful answer!
8
return the_list[i] if len(the_list) > i else None
answered Aug 29, 2012 at 21:00

2 Comments

@JoranBeasley How in the world is a one liner more verbose than various multi-line statements?
@semicolon Another bad metric.
2

Another one-liner:

return((the_list + [None] * i)[i])
answered Oct 4, 2022 at 16:17

3 Comments

I LOVE this :) you only have to write the_list once..
Hum, you're creating a new temporary copy of the whole list plus the list of Nones. I bet this is very inefficient.
That's right, however it is still a simple, one-liner solution.
0
 def getItemOrNone(lst,index):
 return [None,*lst[index:-~index]][~0]
answered Sep 15, 2024 at 13:14

1 Comment

Thank you for your interest in contributing to the Stack Overflow community. This question already has quite a few answers—including one that has been extensively validated by the community. Are you certain your approach hasn’t been given previously? If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.