Come ottenere il primo elemento in un elenco di tuple?


178

Ho un elenco come di seguito in cui il primo elemento è l'id e l'altro è una stringa:

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

Voglio creare un elenco di ID solo da questo elenco di tuple come di seguito:

[1,2]

Userò questo elenco in __inmodo che debba essere un elenco di valori interi.

Risposte:


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

68

Usa la funzione zip per disaccoppiare gli elementi:

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

Modifica (@BradSolomon): quanto sopra funziona per Python 2.x, dove ziprestituisce un elenco.

In Python 3.x, ziprestituisce un iteratore e quanto segue equivale a quanto sopra:

>>> print(list(list(zip(*inpt))[0]))
[1, 2]

questo ha bisogno di un'importazione separata?
JuliandotNut

2
@JuliandotNut No, è una funzione integrata. (in Python 2.x)
WayneSan,

22

Intendi qualcosa come questo?

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

Quello che hai in realtà è un elenco di tupleoggetti, non un elenco di insiemi (come implica la tua domanda originale). Se in realtà è un elenco di insiemi, allora non esiste un primo elemento perché gli insiemi non hanno alcun ordine.

Qui ho creato un elenco semplice perché in genere sembra più utile della creazione di un elenco di tuple a 1 elemento. Tuttavia, puoi facilmente creare un elenco di 1 tuple di elementi semplicemente sostituendole seq[0]con (seq[0],).


L'ho provato. Dà questo errore:int() argument must be a string or a number, not 'QuerySet'
wasimbhalli,

4
@wasimbhalli - int()non si trova da nessuna parte nella mia soluzione, quindi l'eccezione che vedi deve venire più avanti nel codice.
mgilson,

Ho aggiornato la domanda, ho bisogno di usare questo elenco in seguito __inper filtrare i dati
wasimbhalli

che cos'è __in? - Sulla base dell'input di esempio che hai fornito, questo creerà un elenco di numeri interi. Tuttavia, se il tuo elenco di tuple non inizia con numeri interi, non otterrai numeri interi e dovrai renderli interi tramite into provare a capire perché il tuo primo elemento non può essere convertito in un numero intero.
mgilson,

Funziona new_list = [ seq[0] for seq in yourlist if type(seq[0]) == int]?
pR0P

11

Puoi usare "tuple unpacking":

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

Al momento dell'iterazione ogni tupla viene decompressa e i suoi valori sono impostati sulle variabili idxe val.

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

8

Questo è ciò che operator.itemgetterserve.

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

L' itemgetteristruzione restituisce una funzione che restituisce l'indice dell'elemento specificato. È esattamente lo stesso della scrittura

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

Ma trovo che itemgettersia più chiaro ed esplicito .

Questo è utile per fare dichiarazioni di ordinamento compatte. Per esempio,

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

7

Dal punto di vista delle prestazioni, in python3.X

  • [i[0] for i in a]e list(zip(*a))[0]sono equivalenti
  • sono più veloci di list(map(operator.itemgetter(0), a))

Codice

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)

produzione

3.491014136001468e-05

3.422205176000717e-05


6

se le tuple sono uniche, allora può funzionare

>>> 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']
>>> 

4
Questo perderà l'ordine. Potrebbe funzionare con ordereddict, però.
Tim Tisdall,

se 2 o più tuple hanno lo stesso primo elemento della soluzione non funzionerà
kederrac il

3

quando ho corso (come suggerito sopra):

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

invece di tornare:

[1, 2]

Ho ricevuto questo come ritorno:

<map at 0xb387eb8>

Ho scoperto che dovevo usare list ():

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

per restituire correttamente un elenco usando questo suggerimento. Detto questo, sono contento di questa soluzione, grazie. (testato / eseguito utilizzando Spyder, console iPython, Python v3.6)


3

Stavo pensando che potrebbe essere utile confrontare i tempi di esecuzione dei diversi approcci, quindi ho fatto un benchmark (usando la libreria simple_benchmark )

I) Benchmark con tuple con 2 elementi inserisci qui la descrizione dell'immagine

Come ci si può aspettare di selezionare il primo elemento dalle tuple per indice, si 0rivela la soluzione più veloce molto vicino alla soluzione di disimballaggio aspettandosi esattamente 2 valori

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) Punto di riferimento con tuple con 2 o più elementi inserisci qui la descrizione dell'immagine

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

0

Quelle sono tuple, non insiemi. Puoi farlo:

l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]

2
Non proprio quello che viene chiesto
Mad Physicist,

0

puoi decomprimere le tuple e ottenere solo il primo elemento usando una comprensione dell'elenco:

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

produzione:

[1, 2]

questo funzionerà indipendentemente da quanti elementi hai in una tupla:

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

produzione:

[1, 2]

0

Mi chiedevo perché nessuno suggerisse di usare intorpidimento, ma ora dopo aver controllato ho capito. Forse non è il migliore per array di tipo misto.

Questa sarebbe una soluzione in numpy:

>>> import numpy as np

>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.