user265454
user265454

Reputation: 3271

How to get the nth element of a python list or a default if not available

In Python, how can I simply do the equivalent of dictionary.get(key, default) for lists - i.e., how can I simply get the nth element of a list, or a default value if not available?

For example, given a list myList, how can I get 5 if myList is empty, or myList[0] otherwise?

Upvotes: 218

Views: 363195

Answers (14)

Mike Reiche
Mike Reiche

Reputation: 460

I like it more inline, therefore I created a little streams-like library (https://pypi.org/project/tinystream/).

my_list = ["a", "b", "c"]

stream = Stream(my_list)
assert stream[4].absent
assert stream[0].get() == "a"

Since the index element is of type Opt, you can also do more stuff like:

assert stream[4].get('X') == 'X'  # default if absent
assert stream[0].map(str.upper).filter(lambda x: x == 'A').present

Upvotes: 0

With unpacking:

b, = a[n:n+1] or [default]

Upvotes: 4

user3076105
user3076105

Reputation: 416

For a small index, such as when parsing up to k arguments, I'd build a new list of length k, with added elements set to d, as follows:

def fill(l, k, d): 
    return l + (k - len(l)) * [d]

Typical usage:

N = 2
arg_one, arg_two = fill("first_word and the rest".split(maxsplit=N - 1), N, None)
# arg_one == "first_word"
# arg_two == "and the rest"

Same example, with a short list:

arg_one, arg_two = fill("one_word_only".split(maxsplit=N - 1), N, None)
# arg_one == "one_word_only"
# arg_two == None

Upvotes: 0

ezzeddin
ezzeddin

Reputation: 521

Althought this is not a one-liner solution, you can define a function with a default value like so:

def get_val(myList, idx, default=5):
    try:
        return myList[idx]
    except IndexError:
        return default

Upvotes: 2

serv-inc
serv-inc

Reputation: 38187

Combining @Joachim's with the above, you could use

next(iter(my_list[index:index+1]), default)

Examples:

next(iter(range(10)[8:9]), 11)
8
>>> next(iter(range(10)[12:13]), 11)
11

Or, maybe more clear, but without the len

my_list[index] if my_list[index:index + 1] else default

Upvotes: 2

Mathieu CAROFF
Mathieu CAROFF

Reputation: 1462

After reading through the answers, I'm going to use:

(L[n:] or [somedefault])[0]

Upvotes: 2

Scorchio
Scorchio

Reputation: 2871

A cheap solution is to really make a dict with enumerate and use .get() as usual, like

 dict(enumerate(l)).get(7, my_default)

Upvotes: 4

pylang
pylang

Reputation: 44505

... looking for an equivalent in python of dict.get(key, default) for lists

There is an itertools recipes that does this for general iterables. For convenience, you can > pip install more_itertools and import this third-party library that implements such recipes for you:

Code

import more_itertools as mit


mit.nth([1, 2, 3], 0)
# 1    

mit.nth([], 0, 5)
# 5    

Detail

Here is the implementation of the nth recipe:

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(itertools.islice(iterable, n, None), default)

Like dict.get(), this tool returns a default for missing indices. It applies to general iterables:

mit.nth((0, 1, 2), 1)                                      # tuple
# 1

mit.nth(range(3), 1)                                       # range generator (py3)
# 1

mit.nth(iter([0, 1, 2]), 1)                                # list iterator 
# 1  

Upvotes: 16

Joachim Jablon
Joachim Jablon

Reputation: 958

Just discovered that :

next(iter(myList), 5)

iter(l) returns an iterator on myList, next() consumes the first element of the iterator, and raises a StopIteration error except if called with a default value, which is the case here, the second argument, 5

This only works when you want the 1st element, which is the case in your example, but not in the text of you question, so...

Additionally, it does not need to create temporary lists in memory and it works for any kind of iterable, even if it does not have a name (see Xiong Chiamiov's comment on gruszczy's answer)

Upvotes: 55

Harvey
Harvey

Reputation: 5821

Using Python 3.4's contextlib.suppress(exceptions) to build a getitem() method similar to getattr().

import contextlib

def getitem(iterable, index, default=None):
    """Return iterable[index] or default if IndexError is raised."""
    with contextlib.suppress(IndexError):
        return iterable[index]
    return default

Upvotes: 5

gruszczy
gruszczy

Reputation: 42188

l[index] if index < len(l) else default

To support negative indices we can use:

l[index] if -len(l) <= index < len(l) else default

Upvotes: 176

John La Rooy
John La Rooy

Reputation: 304175

(a[n:]+[default])[0]

This is probably better as a gets larger

(a[n:n+1]+[default])[0]

This works because if a[n:] is an empty list if n => len(a)

Here is an example of how this works with range(5)

>>> range(5)[3:4]
[3]
>>> range(5)[4:5]
[4]
>>> range(5)[5:6]
[]
>>> range(5)[6:7]
[]

And the full expression

>>> (range(5)[3:4]+[999])[0]
3
>>> (range(5)[4:5]+[999])[0]
4
>>> (range(5)[5:6]+[999])[0]
999
>>> (range(5)[6:7]+[999])[0]
999

Upvotes: 53

Tim Pietzcker
Tim Pietzcker

Reputation: 336158

try:
   a = b[n]
except IndexError:
   a = default

Edit: I removed the check for TypeError - probably better to let the caller handle this.

Upvotes: 77

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798676

(L[n:n+1] or [somedefault])[0]

Upvotes: 33

Related Questions