2015-06-03 15 views
5

Esiste un modo efficace per unire due elenchi di tuple in python, in base a un valore comune. Attualmente, sto facendo la seguente:Unisci gli elenchi per valore

name = [ 
     (9, "John", "Smith"), 
     (11, "Bob", "Dobbs"), 
     (14, "Joe", "Bloggs") 
     ] 

occupation = [ 
       (9, "Builder"), 
       (11, "Baker"), 
       (14, "Candlestick Maker") 
       ] 

name_and_job = [] 

for n in name: 
    for o in occupation: 
     if n[0] == o[0]: 
      name_and_job.append((n[0], n[1], n[2], o[1])) 


print(name_and_job) 

rendimenti:

[(9, 'John', 'Smith', 'Builder'), (11, 'Bob', 'Dobbs', 'Baker'), (14, 'Joe', 'Bloggs', 'Candlestick Maker')] 

Anche se questo codice funziona perfettamente bene per le piccole liste, è incredibilmente lenta per liste più lunghe con milioni di dischi. C'è un modo più efficiente per scrivere questo?

MODIFICA I numeri nella prima colonna sono univoci.

EDIT Modificato il codice di @John Kugelman leggermente. Aggiunto un get(), nel caso in cui il dizionario nomi non ha una chiave corrispondente nel dizionario occupazione:

>>>> names_and_jobs = {id: names[id] + (jobs.get(id),) for id in names} 
>>>> print(names_and_jobs) 
{9: ('John', 'Smith', None), 11: ('Bob', 'Dobbs', 'Baker'), 14: ('Joe', 'Bloggs', 'Candlestick Maker')} 
+3

Per prestazioni spesso la struttura di dati a destra è la chiave. Usa un dizionario. –

+2

Lasciando la mia risposta cancellata come commento per <10k utenti. * Se * la tua lista è sicura di avere * esattamente * voci corrispondenti, allora puoi usare ['zip'] (https://docs.python.org/2/library/functions.html#zip) insieme a un [elenco comprensione] (https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions) come in '[(x [0], x [1], x [2], y [1]) per x, y in zip (nome, occupazione)] ' –

+0

@BhargavRao Penso che sia una buona ipotesi, perché altrimenti l'OP non mostrerebbe una non corrispondenza nell'esempio? –

risposta

5

Uso dizionari invece di liste piatte.

names = { 
    9: ("John", "Smith"), 
    11: ("Bob", "Dobbs"), 
    14: ("Joe", "Bloggs") 
} 

jobs = { 
    9: "Builder", 
    11: "Baker", 
    14: "Candlestick Maker" 
} 

Se avete bisogno di convertirli in questo formato, si può fare:

>>> {id: (first, last) for id, first, last in name} 
{9: ('John', 'Smith'), 11: ('Bob', 'Dobbs'), 14: ('Joe', 'Bloggs')} 
>>> {id: job for id, job in occupation} 
{9: 'Builder', 11: 'Baker', 14: 'Candlestick Maker'} 

Sarebbe quindi essere un pezzo di torta per unire i due.

names_and_jobs = {id: names[id] + (jobs[id],) for id in names} 
+1

Ciò presuppone che i valori 9, 11 e 14 siano univoci. Cosa succede se questo è solo "anni di esperienza" e non è affatto unico? –

+4

@TravisGriggs Il codice dell'OP li tratta come ID. Presumo che questa sia l'intenzione. –

+4

@TravisGriggs sì ma si sta unendo solo controllando l'uguaglianza per quel numero, quindi puoi assumere che sono univoci –

1
from collections import OrderedDict 
from itertools import chain 

od = OrderedDict() 


for ele in chain(name,occupation): 
    od.setdefault(ele[0], []).extend(ele[1:]) 


print([[k]+val for k,val in od.items()]) 

[[9, 'John', 'Smith', 'Builder'], [11, 'Bob', 'Dobbs', 'Baker'], [14, 'Joe', 'Bloggs', 'Candlestick Maker']] 

Se si desidera che i dati in ordine di come appare nei nomi allora avete bisogno di utilizzare un OrderedDict come dicts normali non sono ordinati.

è anche possibile aggiungere i dati del ciclo creando le tuple desiderati poi basta chiamare od.values ​​per ottenere l'elenco di tuple:

from collections import OrderedDict 
from itertools import chain 

od = OrderedDict() 

for ele in chain(name, occupation): 
    k = ele[0] 
    if k in od: 
     od[k] = od[k] + ele[1:] 
    else: 
     od[k] = ele 

print(od.values()) 
[(9, 'John', 'Smith', 'Builder'), (11, 'Bob', 'Dobbs', 'Baker'), (14, 'Joe', 'Bloggs', 'Candlestick Maker')] 
+0

err * OderederDict *? Troppo whisky? –

+0

@BhargavRao il codice dell'OP sta iterando sui nomi in ordine, usando un normale dict significa che i dati non hanno alcun ordine, tuttavia i nomi appaiono nei nomi questo corrisponderà all'ordine –

+0

Ey! Non hai capito il mio punto;) Ora hai ottenuto il mio voto :) –

Problemi correlati