Cara mendapatkan elemen ke-n dari daftar python atau default jika tidak tersedia

144

Saya mencari yang setara dengan python dictionary.get(key, default)untuk daftar. Apakah ada idiom satu liner untuk mendapatkan elemen ke-n dari daftar atau nilai default jika tidak tersedia?

Misalnya, diberi daftar myList yang ingin saya dapatkan myList[0], atau 5 jika myListdaftar kosong.

Terima kasih.

pengguna265454
sumber

Jawaban:

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

Untuk mendukung indeks negatif, kita dapat menggunakan:

l[index] if -len(l) <= index < len(l) else default
gruszczy
sumber
3
Tidak berfungsi jika daftar Anda tidak memiliki nama, meskipun - misalnya, dalam pemahaman daftar.
Xiong Chiamiov
9
Anda sepertinya lupa dengan indeks negatif. Misalnya. index == -1000000harus kembali default.
nodakai
3
@nodakai, poin bagus. Saya terkadang digigit oleh ini. x[index] if 0 <= index < len(x) else defaultakan lebih baik jika indexbisa menjadi negatif.
Ben Hoyt
3
@nodakai wow - itu adalah contoh yang bagus mengapa mungkin lebih baik menggunakan try / kecuali, daripada mencoba kode dengan benar tes sehingga tidak pernah gagal. Saya masih tidak suka mengandalkan try / kecuali, untuk kasus yang saya tahu akan terjadi, tetapi ini meningkatkan kesediaan saya untuk mempertimbangkannya.
ToolmakerSteve
6
@ToolmakerSteve: Formula Anda untuk valid_index()salah. Indeks negatif yang legal di Python - itu harus -len(l) <= index < len(l).
Tim Pietzcker
57
try:
   a = b[n]
except IndexError:
   a = default

Sunting: Saya menghapus centang untuk TypeError - mungkin lebih baik untuk membiarkan penelepon menangani ini.

Tim Pietzcker
sumber
3
Saya suka ini. Hanya membungkusnya di sekitar fungsi sehingga Anda bisa menyebutnya dengan iterable sebagai argumen. Lebih mudah dibaca.
Noufal Ibrahim
35
(a[n:]+[default])[0]

Ini mungkin lebih baik karena asemakin besar

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

Ini berfungsi karena jika a[n:]daftar kosong jikan => len(a)

Berikut adalah contoh cara kerjanya range(5)

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

Dan ekspresi penuh

>>> (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
John La Rooy
sumber
5
Apakah Anda menulis ini dalam kode aktual tanpa komentar untuk menjelaskannya?
Peter Hansen
1
@ Peter Hansen, hanya jika saya bermain golf;) Namun itu bekerja pada semua versi Python. Jawaban yang diterima hanya berfungsi pada 2,5+
John La Rooy
3
Ini membuat 3 daftar sementara dan mengakses 2 indeks untuk memilih item.
Joachim Jablon
Meskipun saya tidak akan pernah melakukan ini dalam kode "nyata", ini adalah kalimat singkat yang bagus yang dapat saya gunakan dengan mudah dalam python REPL, jadi Anda mendapatkan upvote saya.
Cookyt
next(iter(lst[i:i+1]), default)- Hanya entri lain dalam kompetisi one-liners jelek yang samar.
jfs
28

Baru menemukan bahwa:

next(iter(myList), 5)

iter(l)mengembalikan iterator aktif myList, next()mengkonsumsi elemen pertama iterator, dan memunculkan StopIterationkesalahan kecuali jika dipanggil dengan nilai default, yang merupakan kasus di sini, argumen kedua,5

Ini hanya berfungsi ketika Anda menginginkan elemen ke-1, yang merupakan kasus dalam contoh Anda, tetapi tidak dalam teks pertanyaan Anda, jadi ...

Selain itu, tidak perlu membuat daftar sementara di memori dan berfungsi untuk semua jenis iterable, bahkan jika itu tidak memiliki nama (lihat komentar Xiong Chiamiov pada jawaban gruszczy)

Joachim Jablon
sumber
3
Dikombinasikan dengan jawaban lain: next(iter(myList[n:n+1]), 5) Sekarang berfungsi untuk nelemen th.
Alfe
Itu tidak akan bekerja dengan daftar non. Pada titik ini, cobalah: kecuali sebuah IndexError terbaca seperti ide IMHO yang lebih baik. Juga, itu membuat daftar di memori.
Joachim Jablon
The tryvarian bukanlah satu-kapal (ask diminta oleh OP). Ini hanya berfungsi untuk daftar karena myListmerupakan daftar yang ditentukan oleh OP (lebih tepatnya, ini adalah sesuatu yang dapat diindeks). Membuat salinan dalam memori tidak mahal di sini karena saya membuat daftar satu elemen tunggal (atau tidak ada) di sini. Tentu, sedikit overhead, tetapi tidak layak disebutkan kecuali Anda melakukannya jutaan kali dalam satu lingkaran. Btw, saya kira membuat dan menangkap IndexErrorpengecualian mungkin lebih mahal.
Alfe
jumlah keterbacaan :) Jika Anda pada titik di mana menaikkan IndexError memiliki biaya yang signifikan, mungkin Anda harus melakukan semuanya dengan Python.
Joachim Jablon
20
(L[n:n+1] or [somedefault])[0]
Ignacio Vazquez-Abrams
sumber
1
1 karena ini membuat saya belajar apa yang [] or ...dilakukannya. Namun, saya pribadi hanya akan menggunakan solusi yang diterima, karena mudah dibaca (untuk pemula). Memang, membungkusnya dalam 'def' dengan komentar akan membuat sebagian besar tidak menjadi masalah.
ToolmakerSteve
Bagaimana jika L[n] == Falseatau L[n] == Noneatau L[n] == []lebih global apa pun yang mengevaluasi ke False?
Joachim Jablon
@ JoachimJablon: Masih berfungsi. Potongan mengembalikan daftar, dan [False]itu benar.
Ignacio Vazquez-Abrams
Oh, tidak menyadari daftar itu sudah diperiksa dan bukan nilainya, memang.
Joachim Jablon
Mengapa Anda membungkus ini dalam tuple? Saya pikir myval = l[n:n+1] or [somedefault]akan bekerja dengan baik?
Rotareti
8

... mencari yang setara dengan python dict.get(key, default)untuk daftar

Ada resep itertools yang melakukan ini untuk iterables umum. Untuk kenyamanan, Anda dapat > pip install more_itertoolsdan mengimpor perpustakaan pihak ketiga ini yang mengimplementasikan resep tersebut untuk Anda:

Kode

import more_itertools as mit


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

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

Detail

Berikut adalah implementasi nthresepnya:

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

Seperti dict.get(), alat ini mengembalikan default untuk indeks yang hilang. Itu berlaku untuk iterables umum:

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  
pylang
sumber
2

Solusi murah adalah benar-benar membuat dikte dengan penghitungan dan digunakan .get()seperti biasa, seperti

 dict(enumerate(l)).get(7, my_default)
Scorchio
sumber
1

Menggabungkan @ Joachim dengan yang di atas, bisa Anda gunakan

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

Contoh:

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

Atau, mungkin lebih jelas, tetapi tanpa len

my_list[index] if my_list[index:] else default
serv-inc
sumber
1

Menggunakan Python 3.4 contextlib.suppress(exceptions)untuk membangun getitem()metode yang mirip dengan 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
Harvey
sumber