Bagaimana cara mendapatkan elemen pertama dalam daftar tupel?

178

Saya memiliki daftar seperti di bawah ini di mana elemen pertama adalah id dan yang lainnya adalah string:

[(1, u'abc'), (2, u'def')]

Saya ingin membuat daftar id hanya dari daftar tupel seperti di bawah ini:

[1,2]

Saya akan menggunakan daftar ini __insehingga perlu daftar nilai integer.

wasimbhalli
sumber

Jawaban:

245
>>> a = [(1, u'abc'), (2, u'def')]
>>> [i[0] for i in a]
[1, 2]
Rakesh
sumber
68

Gunakan fungsi zip untuk memisahkan elemen:

>>> inpt = [(1, u'abc'), (2, u'def')]
>>> unzipped = zip(*inpt)
>>> print unzipped
[(1, 2), (u'abc', u'def')]
>>> print list(unzipped[0])
[1, 2]

Sunting (@BradSolomon): Di atas berfungsi untuk Python 2.x, di mana zipmengembalikan daftar.

Dalam Python 3.x, zipmengembalikan iterator dan yang berikut ini setara dengan yang di atas:

>>> print(list(list(zip(*inpt))[0]))
[1, 2]
WayneSan
sumber
apakah ini perlu impor terpisah?
JuliandotNut
2
@JuliandotNut Tidak, ini adalah fungsi bawaan. (dalam Python 2.x)
WayneSan
22

maksud Anda sesuatu seperti ini

new_list = [ seq[0] for seq in yourlist ]

Apa yang sebenarnya Anda miliki adalah daftar tupleobjek, bukan daftar set (seperti pertanyaan awal Anda tersirat). Jika itu sebenarnya adalah daftar set, maka tidak ada elemen pertama karena set tidak memiliki urutan.

Di sini saya telah membuat daftar datar karena umumnya yang tampaknya lebih bermanfaat daripada membuat daftar 1 elemen tuple. Namun, Anda dapat dengan mudah membuat daftar 1 tupel elemen dengan hanya mengganti seq[0]dengan (seq[0],).

mgilson
sumber
Saya mencobanya. Ini memberikan kesalahan ini:int() argument must be a string or a number, not 'QuerySet'
wasimbhalli
4
@ autimbhalli - int()tidak ada dalam solusi saya, jadi pengecualian yang Anda lihat harus datang kemudian dalam kode.
mgilson
Saya telah memperbarui pertanyaan, saya harus menggunakan daftar ini nanti __inuntuk memfilter data
wasimbhalli
apa __in? - Berdasarkan contoh input yang Anda berikan, ini akan membuat daftar bilangan bulat. Namun, jika daftar tupel Anda tidak dimulai dengan bilangan bulat, maka Anda tidak akan mendapatkan bilangan bulat dan Anda harus membuatnya bilangan bulat int, atau mencoba mencari tahu mengapa elemen pertama Anda tidak dapat dikonversi menjadi bilangan bulat.
mgilson
Apakah new_list = [ seq[0] for seq in yourlist if type(seq[0]) == int]bekerja?
pR0Ps
11

Anda dapat menggunakan "tuple unpacking":

>>> my_list = [(1, u'abc'), (2, u'def')]
>>> my_ids = [idx for idx, val in my_list]
>>> my_ids
[1, 2]

Pada waktu iterasi setiap tuple dibongkar dan nilainya diatur ke variabel idxdan val.

>>> x = (1, u'abc')
>>> idx, val = x
>>> idx
1
>>> val
u'abc'
toleransi
sumber
8

Ini untuk apa operator.itemgetter.

>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b
[1, 2]

The itemgetterpernyataan mengembalikan fungsi yang mengembalikan indeks dari elemen yang Anda tentukan. Persis sama dengan menulis

>>> b = map(lambda x: x[0], a)

Tetapi saya menemukan bahwa itemgetteritu lebih jelas dan lebih eksplisit .

Ini berguna untuk membuat pernyataan sortir yang ringkas. Sebagai contoh,

>>> c = sorted(a, key=operator.itemgetter(0), reverse=True)
>>> c
[(2, u'def'), (1, u'abc')]
bcattle
sumber
7

Dari sudut pandang kinerja, di python3.X

  • [i[0] for i in a]dan list(zip(*a))[0]setara
  • mereka lebih cepat dari list(map(operator.itemgetter(0), a))

Kode

import timeit


iterations = 100000
init_time = timeit.timeit('''a = [(i, u'abc') for i in range(1000)]''', number=iterations)/iterations
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = [i[0] for i in a]''', number=iterations)/iterations - init_time)
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = list(zip(*a))[0]''', number=iterations)/iterations - init_time)

keluaran

3.491014136001468e-05

3.422205176000717e-05

mencolok
sumber
6

jika tupelnya unik maka ini bisa berhasil

>>> a = [(1, u'abc'), (2, u'def')]
>>> a
[(1, u'abc'), (2, u'def')]
>>> dict(a).keys()
[1, 2]
>>> dict(a).values()
[u'abc', u'def']
>>> 
Jiri Semmler
sumber
4
Ini akan kehilangan pesanan. Ini mungkin bekerja dengan baik ordereddict.
Tim Tisdall
jika 2 atau lebih tupel memiliki elemen pertama yang sama dari solusi Anda tidak akan berfungsi
kederrac
3

ketika saya berlari (seperti yang disarankan di atas):

>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b

alih-alih kembali:

[1, 2]

Saya menerima ini sebagai pengembalian:

<map at 0xb387eb8>

Saya menemukan saya harus menggunakan daftar ():

>>> b = list(map(operator.itemgetter(0), a))

untuk berhasil mengembalikan daftar menggunakan saran ini. Yang mengatakan, saya senang dengan solusi ini, terima kasih. (diuji / jalankan menggunakan Spyder, konsol iPython, Python v3.6)

James
sumber
3

Saya berpikir bahwa mungkin berguna untuk membandingkan runtime dari pendekatan yang berbeda jadi saya membuat patokan (menggunakan perpustakaan simple_benchmark )

I) Benchmark memiliki tupel dengan 2 elemen masukkan deskripsi gambar di sini

Seperti yang mungkin Anda harapkan untuk memilih elemen pertama dari tuple dengan indeks 0menunjukkan menjadi solusi tercepat yang sangat dekat dengan solusi membongkar dengan mengharapkan tepat 2 nilai

import operator
import random

from simple_benchmark import BenchmarkBuilder

b = BenchmarkBuilder()



@b.add_function()
def rakesh_by_index(l):
    return [i[0] for i in l]


@b.add_function()
def wayneSan_zip(l):
    return list(list(zip(*l))[0])


@b.add_function()
def bcattle_itemgetter(l):
     return list(map(operator.itemgetter(0), l))


@b.add_function()
def ssoler_upacking(l):
    return [idx for idx, val in l]

@b.add_function()
def kederrack_unpacking(l):
    return [f for f, *_ in l]



@b.add_arguments('Number of tuples')
def argument_provider():
    for exp in range(2, 21):
        size = 2**exp
        yield size, [(random.choice(range(100)), random.choice(range(100))) for _ in range(size)]


r = b.run()
r.plot()

II) Benchmark memiliki tupel dengan 2 elemen atau lebih masukkan deskripsi gambar di sini

import operator
import random

from simple_benchmark import BenchmarkBuilder

b = BenchmarkBuilder()

@b.add_function()
def kederrack_unpacking(l):
    return [f for f, *_ in l]


@b.add_function()
def rakesh_by_index(l):
    return [i[0] for i in l]


@b.add_function()
def wayneSan_zip(l):
    return list(list(zip(*l))[0])


@b.add_function()
def bcattle_itemgetter(l):
     return list(map(operator.itemgetter(0), l))


@b.add_arguments('Number of tuples')
def argument_provider():
    for exp in range(2, 21):
        size = 2**exp
        yield size, [tuple(random.choice(range(100)) for _
                     in range(random.choice(range(2, 100)))) for _ in range(size)]

from pylab import rcParams
rcParams['figure.figsize'] = 12, 7

r = b.run()
r.plot()
kederrac
sumber
0

Itu adalah tupel, bukan set. Kamu bisa melakukan ini:

l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]
Lanaru
sumber
2
Tidak benar-benar apa yang diminta
Gila Fisikawan
0

Anda dapat membuka paket tupel dan hanya mendapatkan elemen pertama menggunakan pemahaman daftar:

l = [(1, u'abc'), (2, u'def')]
[f for f, *_ in l]

keluaran:

[1, 2]

ini akan berfungsi tidak peduli berapa banyak elemen yang Anda miliki dalam sebuah tuple:

l = [(1, u'abc'), (2, u'def', 2, 4, 5, 6, 7)]
[f for f, *_ in l]

keluaran:

[1, 2]
kederrac
sumber
0

Saya bertanya-tanya mengapa tidak ada yang menyarankan untuk menggunakan numpy, tetapi sekarang setelah memeriksa saya mengerti. Ini mungkin bukan yang terbaik untuk array tipe campuran.

Ini akan menjadi solusi di numpy:

>>> import numpy as np

>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
CodePrinz
sumber