Найти + Найти далее в Python

Пусть L — список строк.

Вот код, который я использую для поиска строки texttofind в списке L.

texttofind = 'Bonjour'
for s in L:
    if texttofind in s:
        print 'Found!'
        print s
        break

Как бы вы реализовали функцию Найти следующее? Нужно ли хранить индекс ранее найденной строки?


person Basj    schedule 21.12.2013    source источник


Ответы (4)


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

def string_in_list(s, entities):
    """Return elements of entities that contain given string."""
    for e in entities:
        if s in e:
            yield e

huge_list = ['you', 'say', 'hello', 'I', 'say', 'goodbye']  # ...
matches = string_in_list('y', huge_list)  # look for strings with letter 'y'
next(matches)  # first match
next(matches)  # second match

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

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

def string_in_list(s, entities):
    idx = 0
    while idx < len(entities):
        if s in entities[idx]:
            yield entities[idx]
        idx += 1
        if idx >= len(entities):
            # restart from the beginning
            idx = 0
huge_list = ['you', 'say', 'hello']
m = string_in_list('y', huge_list)
next(m)  # you
next(m)  # say
next(m)  # you, again

Другие идеи см. в разделе Как создать повторяющийся генератор.

Еще одно обновление

Прошли годы с тех пор, как я впервые написал это. Вот лучший подход с использованием itertools.cycle:

from itertools import cycle  # will repeat after end

# look for s in items of huge_list
matches = cycle(i for i in huge_list if s in i)
next(matches)
person ChrisP    schedule 21.12.2013
comment
Что можно записать более кратко как matches = (line for line in L if s in line) - person Eric; 22.12.2013
comment
Обратите внимание, что matches.next() устарел в пользу next(matches) - person Eric; 22.12.2013
comment
@ Эрик, спасибо, что указали на это! Я полагаю, что эта функция полезна только в том случае, если для поиска соответствия требуется более сложная обработка. - person ChrisP; 22.12.2013
comment
Я бы заплакал, если бы увидел это в коде. Идеальный кандидат для выражения генератора. - person Paul Draper; 22.12.2013
comment
Спасибо. Действительно ли matches = (line for line in L if s in line) совпадает с кодом с def ... yield ? - person Basj; 22.12.2013
comment
как я могу сделать так, чтобы, когда next(matches) достигает конца, он НАЧИНАЛСЯ с самого начала? - person Basj; 22.12.2013
comment
@Basj, да, это то же самое. Выражения генератора были введены некоторое время назад. Как указывали другие, здесь предпочтительнее синтаксис (...). См. отредактированный ответ, чтобы перезапустить его в начале. - person ChrisP; 22.12.2013

Поиск всех строк в L, которые имеют подстроку s.

[f for f in L if s in f]
person Paul Draper    schedule 21.12.2013

Если вы хотите найти все индексы строк в L, которые содержат s в качестве подстроки,

[i for i in range(0, len(L)) if L[i].find(s) >= 0]
person James King    schedule 21.12.2013

Это найдет следующее, если оно существует. Вы можете обернуть его в функцию и вернуть None/Empty string, если это не так.

L = ['Hello', 'Hola', 'Bonjour', 'Salam']

for l in L:
    if l == texttofind:
        print l
        if L.index(l) >= 0 and L.index(l) < len(L):
            print L[L.index(l)+1]
person Umair A.    schedule 21.12.2013
comment
Это не находит следующий, этот следующий находит - он занимает следующую строку после строки с совпадением - person Eric; 22.12.2013