2010-04-28 2 views
11

Я хочу считать те же элементы из двух списков. Списки могут иметь повторяющиеся элементы, поэтому я не могу преобразовать их в набор и использовать оператор &.Общие элементы между двумя списками, не использующими наборы в Python

a=[2,2,1,1] 
b=[1,1,3,3] 

множество (а) & множество (б) работать
& б не работают

Можно сделать это withoud установить и справочник?

+0

Почему вы не хотите использовать наборы? –

+1

У меня есть повторяющиеся элементы в списке – Thomas

+2

Каковы ожидаемые значения возврата для '[1, 2, 1]' и '[1, 3, 2]'? – SilentGhost

ответ

8

Использование наборов является наиболее эффективным, но вы всегда можете сделать r = [i for i in l1 if i in l2].

+0

Явное отличие: предлагаемый метод set() и set() возвращает одно значение, которое является общим для двух списков (set ([1]) в этом примере), тогда как ваше решение вернет [1, 1] и так на. –

+0

Спасибо, но это еще одно решение для перфоманса? – Thomas

+0

Я хочу функцию, которая возвращает [1,1] – Thomas

11

В 3.x Python (и Python 2.7, когда она выйдет), вы можете использовать collections.Counter для этого:

>>> from collections import Counter 
>>> list((Counter([2,2,1,1]) & Counter([1,3,3,1])).elements()) 
[1, 1] 

Вот альтернатива, используя collections.defaultdict (доступный в Python 2.5 и выше). Он обладает приятным свойством, что порядок результата детерминирован (он по существу соответствует порядку второго списка).

from collections import defaultdict 

def list_intersection(list1, list2): 
    bag = defaultdict(int) 
    for elt in list1: 
     bag[elt] += 1 

    result = [] 
    for elt in list2: 
     if elt in bag: 
      # remove elt from bag, making sure 
      # that bag counts are kept positive 
      if bag[elt] == 1: 
       del bag[elt] 
      else: 
       bag[elt] -= 1 
      result.append(elt) 

    return result 

Для обоих этих решений, число вхождений любого данного элемента x в списке вывода является минимальным из числа вхождений x в двух входных списков. Из вашего вопроса неясно, является ли это поведением, которое вы хотите.

+0

'if bag [elt]:' добавляет элемент 'elt: 0' в сумку, когда' elt in bag' является ложным. Когда (как намекает OP), существует несколько дубликатов, лучше сделать 'if elt в сумке и сумке [elt]:' иначе сумка может раздуваться с бесполезными 0 значениями. –

+0

@John Machin: Хм. Хорошая точка зрения. Альтернативой было бы убедиться, что количество мешков всегда строго положительное, следуя 'bag [elt] - = 1' с' if not bag [elt]: del bag [elt] '. Тогда тест 'if' может быть просто« если elt в сумке », который читается более красиво. Я отредактирую ответ. –

0

SilentGhost, Марк Дикинсон и Lo'oris правы, спасибо за доклад эта проблема - мне нужна общая часть списков, так как:

а = [1,1,1,2]

б = [1,1,3,3]

результат должен быть [1,1]

Извините за комментарий в не подходящем месте - я зарегистрировал сегодня.

Я изменил Ваши решения:

def count_common(l1,l2): 
     l2_copy=list(l2) 
     counter=0 
     for i in l1: 
      if i in l2_copy: 
       counter+=1 
       l2_copy.remove(i) 
     return counter 

l1=[1,1,1] 
l2=[1,2] 
print count_common(l1,l2) 

+4

добро пожаловать! Вы можете отправить сообщение по электронной почте 'team @ stackoverflow.com' и попросить их объединить вашу недавно зарегистрированную учетную запись с предыдущей временной учетной записью. См.: http://meta.stackexchange.com/questions/18232/how-can-one-link-merge-combine-associate-two-stack-overflow-accounts-users-anon –

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