2016-08-18 4 views
1

Я запускаю два запроса в базу данных, результат, который я получаю от каждого, представляет собой список кортежей, который является идеальным. Я хотел бы объединить их в один список кортежей. Эти примеры кортежей:Как присоединиться к двум спискам кортежей без дубликатов

list1 = [('abc', 1), ('def', 2) ... ] 
list2 = [(1000, 'abc'), (2000, 'def'), (3000, 'def') ... ] 

Я хочу создать только один список кортежей и я присоединиться к ним, как это:

q = [] 
for i in list1: 
      for j in list2:   
       if i[0] == (j[1]): 
        i = i + (j[0],) 
        q.append(i) 

Это возвращает дубликаты в своем новом списке q, как я получаю что-то вроде это:

q = [('abc', 1 , 1000) , ('def', 2, 2000), ('def', 2, 2000, 3000) ...] 

Как я могу избежать дублирования, как второй список кортежей в списке q? Я хочу только ('def', 2, 2000, 3000), а не это ('def', 2, 2000), ('def', 2, 2000, 3000)

Я застрял на этом какое-то время, поэтому любая помощь приветствуется. Спасибо

+0

Использование вложенных циклов для этого не является хорошей идеей, если списки большие. Подробнее см. Ниже. –

ответ

5

Использование вложенных циклов в порядке, если ваши списки довольно малы, но вскоре они становятся неэффективными для больших списков. Например, если len (list1) == 10 и len (list2) == 20, код внутри внутреннего цикла выполняется 200 раз.

Вот алгоритм, который строит нужный список кортежей через словарь. Словарь хранит данные кортежа в списках, потому что он более эффективен: его можно добавлять к спискам, тогда как кортежи неизменяемы, поэтому каждый раз, когда вы добавляете элемент в конец кортежа с помощью i = i + (j[0],), вы фактически создаете новый объект кортежа (а также временный набор (j[0],)) и отбрасывание старого, связанного с i.

list1 = [('abc', 1), ('def', 2), ('ghi', 3)] 
list2 = [ 
    (1000, 'abc'), 
    (2000, 'def'), 
    (2100, 'def'), 
    (3000, 'ghi'), 
    (3100, 'ghi'), 
    (3200, 'ghi'), 
] 

# Insert list1 data into a dict of lists 
d = {t[0]:list(t) for t in list1} 

# Append list2 data to the correct list 
for v, k in list2: 
    d[k].append(v) 

# Convert lists back into tuples, using the key order from list1 
result = [tuple(d[k]) for k, _ in list1] 
for t in result: 
    print(t) 

выход

('abc', 1, 1000) 
('def', 2, 2000, 2100) 
('ghi', 3, 3000, 3100, 3200) 

С помощью этого алгоритма, если Len (песни1) == 10 и LEN (песни2) == 20 то есть цикл длины 10, чтобы построить словарь d , цикл длиной 20, чтобы добавить данные списка2 в списки d и еще один цикл длиной 10, чтобы построить окончательный список кортежей. он делает шаги внутри каждой из этих циклов, довольно простой, примерно наравне с вашим i = i + (j[0],), и, очевидно, 40 шагов намного лучше 200. И, конечно, если в списках входных данных было 1000 элементов каждый, тогда мой код займет 3000 циклов, в отличие от один миллион циклов, необходимых для подхода вложенных циклов.

Следует также упомянуть, что этот код поднимет KeyError, если list2 содержит ключ, который находится не в list1. Предположительно, это не проблема для данных, которые вы обрабатываете, так как ваш код (и Sevanteri) молча игнорирует такие ключи. Если вам do нужно обрабатывать такие ключи, это довольно просто сделать, но это делает мой list2 цикл более простым & более эффективным, если ему не нужно обрабатывать недостающие ключи.

+0

Благодарим вас за подробный ответ. Сейчас размер списка составляет всего ~ 20, но в будущем он будет расти. Это лучший долгосрочный вариант – johnfk3

0

Вам не нужно добавлять i во внутренний цикл. Один раз в конце внешнего цикла.

q = [] 
for i in list1: 
    for j in list2: 
     if i[0] == j[1]: 
      i = i + (j[0],) 
    q.append(i) 

Во внешнем цикле была опечатка. Он должен быть list1 вместо list.

+0

Спасибо, я отредактировал типографию, он отлично работает! – johnfk3

+0

Вы можете удалить парик вокруг '(j [1])'. Это не кортеж, а простое значение. –

+0

@LaurentLAPORTE Ах, правда. Даже не заметил этого. : D – Sevanteri