Поиск Python в списках списков
У меня есть список списков двух элементов и вам нужно искать вещи в нем.
Если список:
list =[ ['a','b'], ['a','c'], ['b','d'] ]
Я могу легко найти пару, выполнив
['a','b'] in list
Теперь, есть ли способ увидеть, есть ли у меня пара, в которой строка присутствует только во второй позиции? Я могу это сделать:
for i in range (0, len(list)):
if list[i][1]==search:
found=1
Но есть ли лучший способ без цикла for
? Мне не нужно знать i
или продолжать цикл после его обнаружения.
Ответы
Ответ 1
У вас всегда будет цикл: кто-то может прийти с умным однострочным лайнером, который скрывает цикл в вызове map()
или аналогичный, но он всегда будет там.
Мои предпочтения всегда будут иметь чистый и простой код, если только производительность не является основным фактором.
Здесь возможно более Pythonic версия вашего кода:
data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
for sublist in data:
if sublist[1] == search:
print "Found it!", sublist
break
# Prints: Found it! ['a', 'c']
Он вырывается из цикла, как только находит совпадение.
(У вас есть опечатка, кстати, в ['b''d']
.)
Ответ 2
Здесь питонический способ сделать это:
data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
any(e[1] == search for e in data)
Или... ну, я не собираюсь утверждать, что это "один истинный питонический способ", чтобы сделать это, потому что в какой-то момент становится немного субъективным, что такое Pythonic, а что нет, или какой метод более Pythonic, чем другой. Но использование any()
- это, безусловно, более типичный стиль Python, чем цикл for
, как, например, Ответ RichieHindle,
Конечно, в реализации any
существует скрытый цикл, хотя он выходит из цикла, как только он находит совпадение.
Так как мне было скучно, я сделал выбор времени script, чтобы сравнить производительность различных предложений, изменив некоторые из них по мере необходимости, чтобы сделать API одинаковым. Теперь мы должны помнить, что самый быстрый не всегда лучший, и быть быстрым, определенно, не то же самое, что быть Pythonic. При этом результаты... странные. Видимо, циклы for
очень быстрые, чего я не ожидал, поэтому я бы взял их с солью, не понимая, почему они вышли так, как они делают.
В любом случае, когда я использовал список, заданный в вопросе, с тремя подсписками из двух элементов, от самого быстрого до самого медленного, я получаю следующие результаты:
- Ответ RichieHindle с циклом
for
, с частотой 0,22 мкс
- Первое предложение Terence Honles, которое создает список в 0,36 мкс
- Ответ Pierre-Luc Bedard (последний кодовый блок), на 0.43 мкс
- По существу, привязанный ответ Markus и цикл
for
от исходного вопроса, на 0,48 мкс
- Coady answer, используя
operator.itemgetter()
, при 0,53 мкс
- Достаточно близко, чтобы считать связь между ответом Alex Martelli с ответом
ifilter()
и Anon, при 0,67 мкс (Алекс постоянно примерно на полсекунды быстрее).
- Еще одна достаточно близкая связь между jojo answer, мой, Брэндон Э Тейлор (который идентичен my) и второе предложение Terence Honles, используя
any()
, все входящие в 0.81-0.82 мкс
- И затем user27221 answer с использованием вложенных списков, в 0,95 мкс
Очевидно, что фактические тайминги не имеют никакого значения ни на одном другом оборудовании, но различия между ними должны дать некоторое представление о том, насколько близки разные методы.
Когда я использую более длинный список, все немного меняется. Я начал со списка в вопросе, с тремя подсписками, и добавил еще 197 подписок, в общей сложности 200 подписок каждой из двух. Используя этот более длинный список, вот результаты:
- Ответ RichieHindle, при тех же 0,22 мкс, что и в более коротком списке
- Coady answer, используя
operator.itemgetter()
, снова в 0.53 мкс
- Первое предложение Terence Honles, которое создает список в 0,36 мкс
- Еще одна виртуальная связь между ответ Alex Martelli с ответами
ifilter()
и Anon, на 0,67 мкс
- Снова достаточно близкая связь между моим ответом, идентичным методом Brandon E Taylor's и второе предложение Terence Honles используя
any()
, все входящие в 0.81-0.82 мкс
Это те, которые сохраняют свое первоначальное время, когда список расширен. Остальное, что нет,
- Цикл
for
из исходного вопроса, на 1,24 мкс
- Первое предложение Terence Honles, которое создает список в 7.49 мкс
- Ответ Пьер-Люка Бедарда (последний кодовый блок), в 8.12 мкс
- Ответ Маркуса, в 10.27 мкс
- jojo answer, в 19.87 мкс
- И наконец user27221 answer с использованием вложенных списков в 60.59 мкс
Ответ 3
>>> the_list =[ ['a','b'], ['a','c'], ['b''d'] ]
>>> any('c' == x[1] for x in the_list)
True
Ответ 4
выше всего выглядят хорошо
но вы хотите сохранить результат?
если так...
вы можете использовать следующие
result = [element for element in data if element[1] == search]
то простой
len(result)
позволяет узнать, что-нибудь найдено (и теперь вы можете делать что-то с результатами)
, конечно, это не обрабатывает элементы, длина которых меньше единицы
(которые вы должны проверять, если не знаете, что они всегда превышают
длина 1, и в этом случае вы должны использовать кортеж? (кортежи неизменяемы))
если вы знаете, что все элементы - это заданная длина, которую вы также можете сделать:
any(second == search for _, second in data)
или для len (данные [0]) == 4:
any(second == search for _, second, _, _ in data)
... и я бы рекомендовал использовать
for element in data:
...
вместо
for i in range(len(data)):
...
(для будущих целей, если вы не хотите сохранять или использовать "i", и просто чтобы вы знали
'0' не требуется, вам нужно всего лишь использовать полный синтаксис, если вы начинаете
при ненулевом значении)
Ответ 5
>>> my_list =[ ['a', 'b'], ['a', 'c'], ['b', 'd'] ]
>>> 'd' in (x[1] for x in my_list)
True
Редактирование для добавления:
Оба Дэвида отвечают с помощью any, а мой, используя в, заканчиваются, когда они находят соответствие, поскольку мы используем выражения генератора. Вот тест с использованием бесконечного генератора, чтобы показать, что:
def mygen():
''' Infinite generator '''
while True:
yield 'xxx' # Just to include a non-match in the generator
yield 'd'
print 'd' in (x for x in mygen()) # True
print any('d' == x for x in mygen()) # True
# print 'q' in (x for x in mygen()) # Never ends if uncommented
# print any('q' == x for x in mygen()) # Never ends if uncommented
Мне просто нравится использовать в вместо == и любой.
Ответ 6
Как насчет:
list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'b'
filter(lambda x:x[1]==search,list)
Это вернет каждый список в список списков, при этом второй элемент будет равен поиску.
Ответ 7
У Маркуса есть один способ избежать использования слова for
- здесь другой, который должен иметь гораздо лучшую производительность для длинных the_list
s...:
import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)
Ответ 8
Ничего плохого в использовании gen exp, но если целью является встраивание цикла...
>>> import itertools, operator
>>> 'b' in itertools.imap(operator.itemgetter(1), the_list)
True
Должен быть и самым быстрым.
Ответ 9
k старый пост, но никто не использует выражение списка для ответа: P
list =[ ['a','b'], ['a','c'], ['b','d'] ]
Search = 'c'
# return if it find in either item 0 or item 1
print [x for x,y in list if x == Search or y == Search]
# return if it find in item 1
print [x for x,y in list if y == Search]
Ответ 10
>>> the_list =[ ['a','b'], ['a','c'], ['b','d'] ]
>>> "b" in zip(*the_list)[1]
True
zip()
объединяет множество списков и группирует элементы по индексу, эффективно переносив матрицу списка списков. Звездочка берет содержимое the_list
и отправляет его в zip
в качестве аргументов, поэтому вы эффективно передаете три списка отдельно, что хочет zip
. Осталось только проверить, есть ли "b"
(или что-то еще) в списке, состоящем из элементов с интересующим вас индексом.
Ответ 11
Я думаю, что использование вложенных списков - самый элегантный способ решить эту проблему, потому что промежуточным результатом является позиция, в которой находится элемент. Реализация будет следующей:
list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'c'
any([ (list.index(x),x.index(y)) for x in list for y in x if y == search ] )
Ответ 12
Я искал глубокую находку для словарей и не нашел ее. Основываясь на этой статье, я смог создать следующее. Спасибо и наслаждайтесь!
def deapFind( theList, key, value ):
result = False
for x in theList:
if( value == x[key] ):
return True
return result
theList = [{ "n": "aaa", "d": "bbb" }, { "n": "ccc", "d": "ddd" }]
print 'Result: ' + str (deapFind( theList, 'n', 'aaa'))
Я использую == вместо оператора in, поскольку возвращает true для частичных совпадений. IOW: поиск aa по n-значению возвращает true. Я не думаю, что это было бы желательно.
НТН
Ответ 13
Ниже приведен простой способ найти, где именно находится элемент в списке.
for i in range (0,len(a)):
sublist=a[i]
for i in range(0,len(sublist)):
if search==sublist[i]:
print "found in sublist "+ "a"+str(i)