Python поиск по спискам списков - PullRequest
48 голосов
/ 21 июля 2009

У меня есть список из двух предметов, и мне нужно найти что-то в нем.

Если список:

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 или продолжать цикл после того, как он найден.

Ответы [ 13 ]

68 голосов
/ 21 июля 2009

Вот Pythonic способ сделать это:

data = [['a','b'], ['a','c'], ['b','d']]
search = 'c'
any(e[1] == search for e in data)

Или ... ну, я не собираюсь утверждать, что это "один истинный Pythonic способ" сделать это, потому что в какой-то момент становится немного субъективным, что является Pythonic, а что нет, или какой метод более питонский, чем другой. Но использование any() определенно является более типичным стилем Python, чем цикл for, как, например, RichieHindle ответ ,

Конечно, в реализации any есть скрытый цикл, хотя он выходит из цикла, как только находит совпадение.


Поскольку мне было скучно, я создал временный скрипт для сравнения производительности различных предложений, модифицируя некоторые из них по мере необходимости, чтобы сделать API одинаковым. Теперь мы должны помнить, что самый быстрый не всегда лучший, и быть быстрым - это совсем не то же самое, что быть Pythonic. При этом результаты ... странные. Очевидно, что for петли очень быстрые, а это не то, что я ожидал, поэтому я взял бы их с крошкой соли, не понимая, почему они вышли так, как они.

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

  1. ответ RichieHindle с петлей for с тактовой частотой 0,22 мкс
  2. Первое предложение Теренса Хонлса , которое создает список, при 0,36 мкс
  3. Ответ Пьера-Люка Бедара (последний кодовый блок) , при 0,43 мкс
  4. По существу связаны между ответом Маркуса и for петлей из исходного вопроса , при 0,48 мкс
  5. Ответ Coady с использованием operator.itemgetter(), при 0,53 мкс
  6. Достаточно близко, чтобы считаться связующим звеном между ответом Алекса Мартелли с ifilter() и ответом Анона при 0,67 мкс (ответ Алекса примерно на полсекунды быстрее)
  7. Еще одна достаточно тесная связь между ответом Джоджо , моим, Брэндона Э. Тейлора (который идентичен моему) и вторым предложением Теренса Хонлеса с использованием any(), все поступают при 0,81-0,82 мкс
  8. А затем ответ пользователя 27221 с использованием понимания вложенного списка, при 0,95 мкс

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

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

  1. ответ RichieHindle , с теми же 0,22 мкс, что и с более коротким списком
  2. Ответ Coady с использованием operator.itemgetter(), снова при 0,53 мкс
  3. Первое предложение Теренса Хонлеса , которое создает список, при 0,36 мкс
  4. Еще одна виртуальная связь между ответом Алекса Мартелли с ifilter() и ответом Анона , при 0,67 мкс
  5. Опять достаточно тесная связь между моим ответом, идентичным методом Брэндона Э. Тейлора и вторым предложением Теренса Хонлеса с использованием any(), все поступают в 0,81-0,82 мкс

Это те, которые сохраняют свое первоначальное время при расширении списка. Остальные, которые этого не делают,

  1. Петля for из исходный вопрос , при 1,24 мкс
  2. Первое предложение Теренса Хонлса , которое создает список, при 7,49 мкс
  3. Ответ Пьера-Люка Бедара (последний кодовый блок) , при 8,12 мкс
  4. ответ Маркуса , при 10,27 мкс
  5. ответ Jojo , при 19,87 мкс
  6. И, наконец, ответ пользователя 27221 с использованием понимания вложенного списка, при 60,59 мкс
39 голосов
/ 21 июля 2009

У вас всегда будет цикл - кто-то может прийти с умной однострочником, который скрывает цикл в вызове на 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'].)

16 голосов
/ 21 июля 2009
>>> the_list =[ ['a','b'], ['a','c'], ['b''d'] ]
>>> any('c' == x[1] for x in the_list)
True
13 голосов
/ 21 июля 2009

выше всего хорошо выглядеть

а вы хотите сохранить результат?

если так ...

Вы можете использовать следующие

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» не требуется, вам нужно использовать полный синтаксис, только если вы начинаете при ненулевом значении)

9 голосов
/ 21 июля 2009
>>> 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

Мне просто нравится просто использовать в вместо обоих == и any .

6 голосов
/ 27 ноября 2012

А как же:

list =[ ['a','b'], ['a','c'], ['b','d'] ]
search = 'b'

filter(lambda x:x[1]==search,list)

Это вернет каждый список в списке списков, второй элемент будет равен поиску.

4 голосов
/ 21 июля 2009

У Маркуса есть один способ избежать использования слова for - вот еще один, который должен иметь гораздо лучшую производительность при длительных the_list с ...:

import itertools
found = any(itertools.ifilter(lambda x:x[1]=='b', the_list)
3 голосов
/ 21 июля 2009

Нет ничего плохого в использовании gen exp, но если цель состоит в том, чтобы встроить цикл ...

>>> import itertools, operator
>>> 'b' in itertools.imap(operator.itemgetter(1), the_list)
True

Должно быть и самым быстрым.

2 голосов
/ 24 августа 2013

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]
1 голос
/ 20 сентября 2018

Я искал глубокий поиск словарей и не нашел ни одного. На основании этой статьи мне удалось создать следующее. Спасибо и наслаждайтесь !!

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, поскольку in возвращает true для частичных совпадений. IOW: поиск aa по клавише n возвращает true. Я не думаю, что это было бы желательно.

НТН

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...