Bagaimana cara mengekstrak elemen ke-n dari daftar tupel?


112

Saya mencoba untuk mendapatkan elemen ke-n dari daftar tupel.

Saya punya sesuatu seperti:

elements = [(1,1,1),(2,3,7),(3,5,10)]

Saya ingin mengekstrak hanya elemen kedua dari setiap tupel ke dalam daftar:

seconds = [1, 3, 5]

Saya tahu bahwa itu bisa dilakukan dengan satu forloop tetapi saya ingin tahu apakah ada cara lain karena saya memiliki ribuan tupel.

Jawaban:


185
n = 1 # N. . .
[x[n] for x in elements]

34

Ini juga berfungsi:

zip(*elements)[1]

(Saya terutama memposting ini, untuk membuktikan kepada diri saya sendiri bahwa saya telah berhasil zip...)

Lihat aksinya:

>>> help(zip)

Bantuan tentang zip fungsi built-in di modul builtin :

zip(...)

zip (seq1 [, seq2 [...]]) -> [(seq1 [0], seq2 [0] ...), (...)]

Kembalikan daftar tupel, di mana setiap tupel berisi elemen ke-i dari setiap urutan argumen. Daftar yang dikembalikan panjangnya dipotong sesuai dengan urutan argumen terpendek.

>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> zip(*elements)
[(1, 2, 3), (1, 3, 5), (1, 7, 10)]
>>> zip(*elements)[1]
(1, 3, 5)
>>>

Hal rapi yang saya pelajari hari ini: Gunakan *listdalam argumen untuk membuat daftar parameter untuk suatu fungsi ...

Catatan : Dalam Python3, zipkembalikan iterator, jadi gunakan list(zip(*elements))untuk mengembalikan daftar tupel.


2
dan gunakan **dictuntuk membuat argumen kata kunci: def test(foo=3, bar=3): return foo*barlalud = {'bar': 9, 'foo'=12}; print test(**d)
Wayne Werner

@Wayne Werner: Ya. Ini semua hanya pengetahuan pasif (saya tidak sering menggunakannya) - tetapi ada baiknya diingatkan sekarang dan nanti sehingga Anda tahu di mana / apa yang harus dicari ...
Daren Thomas

1
Kisah nyata - saya menemukan bahwa dalam apa pun yang saya gunakan cukup sering (Python, vim), saya cenderung untuk pengingat kebutuhan rapi / fitur keren yang saya sudah lupa karena saya tidak menggunakannya yang sering.
Wayne Werner

sintaks daftar * cukup berguna. ada ide di mana ini dijelaskan dalam dokumentasi resmi python?
pengguna1748155

Saya hanya menemukannya di tutorial: docs.python.org/2/tutorial/…
Daren Thomas

30

Saya tahu bahwa itu bisa dilakukan dengan FOR tetapi saya ingin tahu apakah ada cara lain

Ada cara lain. Anda juga dapat melakukannya dengan map dan itemgetter :

>>> from operator import itemgetter
>>> map(itemgetter(1), elements)

Ini masih melakukan perulangan secara internal dan itu sedikit lebih lambat dari pemahaman daftar:

setup = 'elements = [(1,1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))

Hasil:

Metode 1: 1.25699996948
Metode 2: 1.46600008011

Jika Anda perlu mengulang daftar maka gunakan a forbaik-baik saja.


2
Tambahan kecil: Dalam python-3.x benchmark akan menunjukkan bahwa peta hanya membutuhkan sepersekian milidetik. Itu karena itu akan mengembalikan iterator. method2 = 'list (map (itemgetter (1), elements))' menampilkan perilaku lama.
Maik Beckmann

12

Menemukan ini ketika saya sedang mencari cara mana yang tercepat untuk menarik elemen kedua dari daftar 2-tupel. Bukan yang saya inginkan tetapi menjalankan tes yang sama seperti yang ditunjukkan dengan metode ke-3 plus menguji metode zip

setup = 'elements = [(1,1) for _ in range(100000)];from operator import itemgetter'
method1 = '[x[1] for x in elements]'
method2 = 'map(itemgetter(1), elements)'
method3 = 'dict(elements).values()'
method4 = 'zip(*elements)[1]'

import timeit
t = timeit.Timer(method1, setup)
print('Method 1: ' + str(t.timeit(100)))
t = timeit.Timer(method2, setup)
print('Method 2: ' + str(t.timeit(100)))
t = timeit.Timer(method3, setup)
print('Method 3: ' + str(t.timeit(100)))
t = timeit.Timer(method4, setup)
print('Method 4: ' + str(t.timeit(100)))

Method 1: 0.618785858154
Method 2: 0.711684942245
Method 3: 0.298138141632
Method 4: 1.32586884499

Jadi lebih dari dua kali lebih cepat jika Anda memiliki 2 pasangan tupel untuk hanya dikonversi ke dikt dan mengambil nilainya.


Ini mungkin jelas tetapi saya akan menyebutkan dict(elements).values()akan menghasilkan dikt satu elemen sebagai lawan dari komprahensi daftar atau peta. Ini persis seperti yang saya inginkan (saya tertarik dengan touple unik) (+1 dan terima kasih banyak atas posting) tetapi orang lain mungkin bertanya-tanya mengapa dict lebih cepat - ini tidak mengalokasikan memori tetapi hanya memeriksa elemen yang ada.
Greg0ry

6

Pengaturan waktu untuk Python 3.6 untuk mengekstraksi elemen kedua dari daftar 2-tupel.

Juga, menambahkan numpymetode array, yang lebih sederhana untuk dibaca (tapi bisa dibilang lebih sederhana daripada pemahaman daftar).

from operator import itemgetter
elements = [(1,1) for _ in range(100000)]

%timeit second = [x[1] for x in elements]
%timeit second = list(map(itemgetter(1), elements))
%timeit second = dict(elements).values()
%timeit second = list(zip(*elements))[1]
%timeit second = np.array(elements)[:,1]

dan pengaturan waktu:

list comprehension:  4.73 ms ± 206 µs per loop
list(map):           5.3 ms ± 167 µs per loop
dict:                2.25 ms ± 103 µs per loop
list(zip)            5.2 ms ± 252 µs per loop
numpy array:        28.7 ms ± 1.88 ms per loop

Perhatikan bahwa map()dan zip()jangan mengembalikan daftar lagi, maka konversi eksplisit.



1

Menggunakan islicedan chain.from_iterable:

>>> from itertools import chain, islice
>>> elements = [(1,1,1),(2,3,7),(3,5,10)]
>>> list(chain.from_iterable(islice(item, 1, 2) for item in elements))
[1, 3, 5]

Ini dapat berguna saat Anda membutuhkan lebih dari satu elemen:

>>> elements = [(0, 1, 2, 3, 4, 5), 
                (10, 11, 12, 13, 14, 15), 
                (20, 21, 22, 23, 24, 25)]
>>> list(chain.from_iterable(islice(tuple_, 2, 5) for tuple_ in elements))
[2, 3, 4, 12, 13, 14, 22, 23, 24]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.