2015-06-03 3 views
5

Есть ли эффективный способ объединения двух списков кортежей в python, основанных на общем значении. В настоящее время я делаю следующее:Объединить списки по значению

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) 

возвращается:

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

Хотя этот код работает прекрасно для небольших списков, это невероятно медленно для длинных списков с миллионами записей. Есть ли более эффективный способ написать это?

EDIT Номера в первом столбце уникальны.

EDIT Измененный код @John Kugelman. Добавленный Get(), только в том случае, словарь имен не имеет соответствующий ключ в словаре оккупационного:

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

Для выполнения часто правая структура данных является ключевым. Используй словарь. –

+2

Оставляя мой удаленный ответ в качестве комментария для пользователей <10k. * Если * ваш список уверен в наличии * точно совпадающих записей, то вы можете использовать ['zip'] (https://docs.python.org/2/library/functions.html#zip) вместе с [списком (https://docs.python.org/2/tutorial/datastructures.html#list-comprehensions), как в [[x [0], x [1], x [2], y [1]) для x, y в zip (имя, род занятий)] ' –

+0

@BhargavRao Я думаю, что это справедливое предположение, почему еще бы OP не показывал несоответствие в примере? –

ответ

5

Используйте словари вместо плоских списков.

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

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

Если вам нужно преобразовать их в этот формат, вы можете сделать:

>>> {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'} 

Было бы затем быть кусок пирога, чтобы объединить два.

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

Это предполагает, что значения 9, 11 и 14 уникальны. Что, если это всего лишь «многолетний опыт», а не уникальный? –

+4

@TravisGriggs Код OP обрабатывает их как идентификаторы. Я предполагаю, что это намерение. –

+4

@TravisGriggs да, но он сливается, только проверяя равенство для этого числа, поэтому вы можете предположить, что они уникальны. –

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

Если вы хотите, чтобы данные, заказанные, как представляется, в именах, то вам нужно использовать OrderedDict, как нормальные dicts неупорядоченны.

Вы также можете добавить данные в цикле создания требуемого кортежи, то просто звоню od.values, чтобы получить список кортежей:

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 *? Слишком много виски? –

+0

@BhargavRao код OP итерирует имена по порядку, используя обычный dict, будет означать, что данные не имеют порядка, однако имена отображаются в именах, это будет соответствовать порядку –

+0

Ey! Вы не поняли мою точку зрения;) Теперь вы получили мой голос :) –

Смежные вопросы