найдите минимальное количество слов (расстояние) между повторяющимися вхождениями строки поиска во входной строке

#python

#python

Вопрос:

Вот тестовые примеры для кода:

    • строка — 'Tim had been saying that he had been there'
    • Поиск — 'had'
    • ожидаемый результат — 4
    • строка — 'he got what he got and what he wanted'
    • Поиск — 'he'
    • ожидаемый результат — 2
 def return_distance(input, search):
    words = input.split()
    distance = None
    
    indx = []
    if not input or not search:
        return None
    else:
        if words.count(search) >1:
            indx = [ index for index, word in enumerate(words) if word == search]
            distance = indx[1] - indx[0]
            for i  in range(len(indx)-1):
                distance = min(distance, indx[i 1] - indx[i])-1
    
    return distance
  

Я думаю, как оптимизировать код. Я признаю, что это плохо написано.

Комментарии:

1. Итак, код работает, и вы хотите его оптимизировать? Оптимизировать для удобства чтения, производительности …?

2. Спасибо за форматирование @ggorlen

3. да, больше похоже на pythonic

4. Перед оптимизацией я бы предпочел сделать это правильно . Вы получаете ошибку имени для search_str . И после исправления вы, например, терпите неудачу, return_distance('x o x x o x', 'x') возвращая 1 вместо 0 .

5. Спасибо, что указали на ошибку в коде. Исправлено @превосходный дождь

Ответ №1:

Как насчет

 def min_distance_between_words(sentence, word):
    idxes = [i for i, e in enumerate(sentence.split()) if e == word]
    return min([y - x - 1 for x, y in zip(idxes, idxes[1:])])
  

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

Поскольку поведение не определено, когда в предложении нет слова, оно выдает ошибку, но вы можете добавить проверку для этого и при желании вернуть значение по вашему выбору, используя min ‘s default параметр:

 def min_distance_between_words(sentence, word):
    idxes = [i for i, e in enumerate(sentence.split()) if e == word]
    return min([y - x - 1 for x, y in zip(idxes, idxes[1:])], default=None)
  

Кроме того, присвоение имени переменной input перезаписывает встроенное и return_distance является довольно неоднозначным именем для функции.

Добавление предварительного условия для параметров для, None как это делается с if not input or not search: , обычно не выполняется в Python (мы предполагаем, что вызывающий объект всегда будет передавать строку и придерживаться контракта функции).

Если вы хотите обобщить это дальше, переместите split() обязанность в домен вызывающего объекта, который позволяет функции работать с произвольными итерациями:

 def min_distance_between_occurrences(it, target):
    idxes = [i for i, e in enumerate(it) if e == target]
    return min([y - x - 1 for x, y in zip(idxes, idxes[1:])], default=None)
  

Вызов с:

 min_distance_between_occurrences("a b c a".split(), "a")
min_distance_between_occurrences([(1, 2), (1, 3), (1, 2)], (1, 2))
  

Рефакторинг в сторону, как указано в комментариях, исходный код неверен. Проблемы включают:

  • search_str не существует. Вы, вероятно, имели в виду search .
  • distance и min_dist на самом деле не работают вместе. Выберите одно или другое и используйте его для всех минимальных вычислений.
  • min(min_dist, indx[i 1] - indx[i])-1 вычитает 1 в неправильном месте, сбрасывая количество.

Вот потенциальное решение этих проблем:

 def return_distance(input, search):
    words = input.split()
    distance = None

    if words.count(search) > 1:
        indx = [index for index, word in enumerate(words) if word == search]
        distance = indx[1] - indx[0] - 1
        #                           ^^^^

        for i  in range(len(indx) - 1):
            distance = min(distance, indx[i 1] - indx[i] - 1)
            #                                           ^^^^
            
    return distance
  

Комментарии:

1. Большое спасибо за красивое объяснение @ggorlen

Ответ №2:

Один из способов — использовать min с пониманием списка на indx

min_dist = min([(indx[i 1] - indx[i]-1) for i in range(len(indx)-1) ])