2013-11-07 3 views
1

У меня есть следующий list_A:Как улучшить следующий список в список в Python?

['0', '1', '2', '3', '4', '5', '6', '7'] 

и этот другой list_B:

['2','6','7'] 

Я хотел бы, чтобы проверить это: Для каждого элемента в «list_A», если это один из элементов "list_B"

Итак:

for 0 <-> are you one of these? ['2','6','7'] 
for 1 <-> are you one of these? ['2','6','7'] 
for 2 <-> are you one of these? ['2','6','7'] 

И в конце концов, я бы хотел придумать «list_C», который идентичен «list_A» с точки зрения подсчета элементов, но больше похоже на карту, которая выглядит следующим образом:

['-1', '-1', '2', '-1', '-1', '-1', '6', '7'] 

Который является: «-1» для каждого несовпадающих элемент и «я» для каждого подходящего. Очевидно, что я делаю это с 2 вложен для каждого цикла, и она работает:

myStateMap = [] 

for a in list_A: 
    elementString = -1 
    for b in list_B: 
     if a == b: 
      # Update the elementString in case of a match 
      elementString = a 
      print "\tMatch" 
     else: 
      pass 
      print "\tNO Match!" 
    # Store the elementString 
    myStateMap.append(elementString) 

Вопрос: Как бы оптимизировать это? Как бы вы сделали это короче и эффективнее?

+0

Список всегда сортируется? или это случайные данные? –

ответ

4

Вы можете использовать list comprehension:

>>> [('-1' if item not in list_B else item) for item in list_A] 
['-1', '-1', '2', '-1', '-1', '-1', '6', '7'] 
+0

Короткие и сладкие, очень приятно! – cforbish

+0

Отлично! Работает! Большое спасибо! – symbolix

4

Используйте список понимание с условным выражением:

[i if i in list_B else '-1' for i in list_A] 

Демо:

>>> list_A = ['0', '1', '2', '3', '4', '5', '6', '7'] 
>>> list_B = ['2','6','7'] 
>>> [i if i in list_B else '-1' for i in list_A] 
['-1', '-1', '2', '-1', '-1', '-1', '6', '7'] 

если list_B велико, вы должны сделать вместо него:

set_B = set(list_B) 

, чтобы ускорить тестирование членства. in в списке имеет линейную стоимость (чем больше элементов нужно отсканировать, тем больше требуется), в то время как один и тот же тест против множества принимает постоянные затраты (независимо от количества значений в наборе).

Для вашего конкретного примера, используя набор уже быстрее:

>>> timeit.timeit("[i if i in list_B else '-1' for i in list_A]", "from __main__ import list_A, list_B") 
1.8152308464050293 
>>> timeit.timeit("set_B = set(list_B); [i if i in set_B else '-1' for i in list_A]", "from __main__ import list_A, list_B") 
1.6512861251831055 

но если list_A отношения list_B различны и размеры невелики:

>>> list_A = ['0', '1', '2', '3'] 
>>> list_B = ['2','6','8','10'] 
>>> timeit.timeit("[i if i in list_B else '-1' for i in list_A]", "from __main__ import list_A, list_B") 
0.8118391036987305 
>>> timeit.timeit("set_B = set(list_B); [i if i in set_B else '-1' for i in list_A]", "from __main__ import list_A, list_B") 
0.9360401630401611 

Тем не менее, в общем кейс стоит использовать с помощью комплектов.

+0

Это правда? https://wiki.python.org/moin/TimeComplexity упоминает O (1) в среднем, но O (n) в худшем случае для набора запросов. –

+0

@SimeonVisser: худший случай в крайне маловероятном сценарии, что все значения вставили хэш в один и тот же начальный слот, что привело к постоянным хэш-коллизиям. Кстати, это также причина того, что Python 3.3 представил случайное хеш-семя; чтобы злоумышленник не мог подавать ваши ключи приложений, гарантированные для создания хеш-коллизий и, следовательно, для DOS вашего приложения. –

+0

Спасибо, это интересно. Тем более разумно начать планирование этого неуловимого обновления Python 3. –

0

Самый быстрый способ оптимизации - использовать if a in list_B: вместо внутреннего контура. Таким образом, новый код будет выглядеть следующим образом:

for a in list_A: 
    if a in list_B: 
     myStateMap.append(a) 
     print '\tMatch' 
    else: 
     print '\tNO Match!' 
     myStateMap.append(-1) 
+0

Если мы говорим исключительно об алгоритмах, оба решения аналогичны, a в list_b выполняет то же самое, что и внутренний цикл в вопросе OP. Однако ваше решение действительно ускоряет работу в основном потому, что оператор ** in ** является встроенным python и что поиск выполняется внутри, что намного быстрее, чем скомпилированная версия. –

0

Вот еще один короткий список понимания пример, который немного отличается от остальных:

a=[1,2,3,4,5,6,7] 
b=[2,5,7] 
c=[x * (x in b) for x in a] 

Что дает c = [0, 2, 0, 0, 5, 6, 7].Если ваши элементы списка фактически являются строками, как они кажутся, то вы либо получаете пустую строку '', либо исходную строку. Это использует неявное преобразование логического значения (x in b) либо 0, либо 1, прежде чем умножать его на исходное значение (которое в случае строк является «повторным конкатенацией»).

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