Як отримати n-й елемент списку python або за замовчуванням, якщо вони відсутні


144

Я шукаю еквівалент у python dictionary.get(key, default)для списків. Чи є якась ідіома вкладиша, щоб отримати n-й елемент списку або значення за замовчуванням, якщо немає?

Наприклад, давши список myList, який я хотів би отримати myList[0], або 5, якщо myListце порожній список.

Дякую.

Відповіді:


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

Для підтримки негативних показників ми можемо використовувати:

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

3
Не працює, якщо ваш список не має імені, - наприклад, у розумінні списку.
Xiong Chiamiov

9
Ви, здається, забули випадок негативного індексу. Напр. index == -1000000повинен повернутися default.
nodakai

3
@nodakai, хороший момент. Мене іноді це кусало. x[index] if 0 <= index < len(x) else defaultбуло б краще, якщо indexколи-небудь може бути негативним.
Бен Хойт

3
@nodakai wow - це чудовий приклад того, чому може бути краще використовувати try / за винятком, ніж намагатися правильно кодувати тест, щоб він ніколи не вийшов з ладу. Я все ще не люблю покладатися на спробу / за винятком випадків, про які я знаю, що станеться, але це збільшує мою готовність розглянути це.
ToolmakerSteve

6
@ToolmakerSteve: Ваша формула для valid_index()невірна. Негативні показники є законними в Python - так і має бути -len(l) <= index < len(l).
Тім Піцкер

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

Редагувати: Я видалив чек на TypeError - можливо, краще дозволити абоненту впоратися з цим.


3
Мені подобається це. Просто оберніть його навколо функції, щоб можна було викликати її ітерабельним аргументом. Легше читати.
Нуфал Ібрагім

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

Це, мабуть, краще, оскільки aстає більше

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

Це працює, тому що якщо a[n:]це порожній список, якщоn => len(a)

Ось приклад того, як це працює range(5)

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

І повний вираз

>>> (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

5
Ви б написали це у фактичному коді без коментаря, щоб пояснити це?
Пітер Хансен

1
@ Peter Hansen, тільки якщо я займався гольфом;) Однак він працює на всіх версіях Python. Прийнята відповідь працює лише у версії 2.5+
Джон Ла Руй

3
Однак він пропонує створити 3 тимчасові списки та отримати доступ до 2 індексів для вибору елемента.
Йоахім Яблон

Хоча я ніколи цього не роблю в "справжньому" коді, це приємний короткий однокласник, який я легко можу використовувати в відповіді на python REPL, так що ви отримаєте мою нагороду.
Кук

next(iter(lst[i:i+1]), default)- лише черговий запис у криптованому потворному конкурсі однолінійних.
jfs

28

Щойно виявив, що:

next(iter(myList), 5)

iter(l)повертає ітератор myList, next()споживає перший елемент ітератора і піднімає aStopIteration помилку, за винятком випадків, коли викликається зі значенням за замовчуванням, що є випадком тут, другий аргумент,5

Це працює лише тоді, коли ви хочете, щоб 1-й елемент, як це у вашому прикладі, але не в тексті запитання, тож ...

Крім того, йому не потрібно створювати тимчасові списки в пам'яті, і він працює для будь-якого вибору, навіть якщо він не має імені (див. Коментар Xiong Chiamiov щодо відповіді gruszczy)


3
У поєднанні з іншими відповідями: next(iter(myList[n:n+1]), 5) Тепер він працює для nго елемента.
Альфе

Це не спрацювало б із списками, які не є. На цьому етапі спробуйте: за винятком того, що IndexError читає як кращу ідею IMHO. Також він створює список в пам'яті.
Йоахім Яблон

tryВаріант не один вкладиш (ASK , запитуваний OP). Він працює лише для списків, оскільки myListце список, визначений ОП (якщо бути точним, він є чимось індексується). Створення копії в пам'яті тут не дорого, тому що я створюю тут один єдиний (або жоден) елемент. Звичайно, трохи накладні, але не варто згадувати, якщо ви не зробите це мільйони разів у циклі. Btw, я думаю, створення та IndexErrorвилучення винятків, ймовірно, дорожче.
Альфе

читабельність підраховується :) Якщо ви знаходитесь в точці, коли підвищення IndexError має значну вартість, можливо, вам варто зробити це все в Python.
Йоахім

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

1
+1, тому що це змусило мене піти вчитися, що [] or ...робив. Однак я особисто використовував би прийняте рішення, оскільки воно читається легко (для новачків). Звернувшись, загортання його у коментарі з дефініцією зробить це значною мірою проблемою.
ToolmakerSteve

Що робити, якщо L[n] == Falseабо L[n] == Noneчи L[n] == []більше глобально що-небудь, що оцінює помилкове?
Іоахім Яблон

@JoachimJablon: Все ще працює. Фрагмент повертає список, і [False]це правда.
Ігнасіо Васкес-Абрамс

О, не зрозумів, що список перевіряється, а не значення, дійсно.
Йоахім Яблон

Чому ви загортаєте це в кортеж? Думаю myval = l[n:n+1] or [somedefault], спрацювало б добре?
Ротарети

8

... шукає еквівалент у python dict.get(key, default)для списків

Є рецепти itertools, які роблять це для загальних ітерабелів. Для зручності можна> pip install more_itertools імпортувати цю сторонню бібліотеку, яка реалізує такі рецепти для вас:

Код

import more_itertools as mit


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

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

Деталь

Ось реалізація nthрецепту:

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

Мовляв dict.get(), цей інструмент повертає за замовчуванням пропущені індекси. Це стосується загальних ітерабелей:

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  

2

Дешеве рішення - насправді скласти диктант із перерахуванням та використовувати, .get()як зазвичай, як

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

1

Поєднавши @ Joachim's з вищезазначеним, ви могли б скористатися

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

Приклади:

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

Або, можливо, більш зрозуміло, але без того len

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

1

Використання Python 3.4's contextlib.suppress(exceptions)для побудови getitem()методу, подібного до 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.