Заменить строковые символы их индексом слова - PullRequest
0 голосов
/ 23 февраля 2019

Обратите внимание на два последовательных пробела в этой строке:

string = "Hello there  everyone!"

for i, c in enumerate(string):
    print(i, c)

 0 H
 1 e
 2 l
 3 l
 4 o
 5
 6 t
 7 h
 8 e
 9 r
10 e
11
12
13 e
14 v
15 e
16 r
17 y
18 o
19 n
20 e
21 !

Как создать список длиной len(string), в котором каждое значение содержит количество слов до этой точки в строке?

Ожидаемый результат: 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2

Единственный способ, которым я мог это сделать, - это циклически проходить по каждому символу, устанавливать флаг space=True и увеличивать счетчик каждый раз, когда я нажимаю символ без пробела, когда space == True.Вероятно, это потому, что я больше всего разбираюсь в C, но я хотел бы изучить более Pythonic способ решить эту проблему.

1 Ответ

0 голосов
/ 23 февраля 2019

Я чувствую, что ваше решение не так уж далеко от того, чтобы быть питоническим.Возможно, вы можете использовать оператор zip, чтобы перебрать вашу строку два на два, а затем просто обнаружить локальные изменения (от пробела до буквы -> это новое слово):

string = "Hello there  everyone!"

def word_index(phrase):
  nb_words = 0
  for a, b in zip(phrase, phrase[1:]):
    if a == " " and b != " ":
      nb_words += 1
    yield nb_words

print(list(word_index(string)))

Здесь также используются генераторы , что довольно часто встречается в python (см. Документацию для ключевого слова yield ).Вероятно, вы можете сделать то же самое, используя itertools.accumulate вместо цикла for, но я не уверен, что он не запутает код (см. Третий элемент из Zen of Python ).Вот как это будет выглядеть, обратите внимание, что я использовал лямбда-функцию здесь, не потому, что я думаю, что это лучший выбор, а просто потому, что я не смог найти никакого значимого имени функции:

import itertools

def word_index(phrase):
  char_pairs = zip(phrase, phrase[1:])
  new_words = map(lambda p: int(p[0] == " " and p[1] != " "), char_pairs)
  return itertools.accumulate(new_words)

Эта втораяверсия, аналогичная первой, возвращает итератор .Обратите внимание, что использование итераторов, как правило, является хорошей идеей, поскольку в нем не делается никаких предположений о том, хочет ли ваш пользователь что-либо создавать.Если пользователь хочет преобразовать итератор it в список, он всегда может вызвать list(it), как я делал в первом фрагменте кода.Итераторы просто выдают вам значения одно за другим: в любой момент времени в памяти присутствует только одно значение:

for word_index in word_index(string):
    print(word_index)

Обратите внимание, что phrase[1:] делает копию изфраза, которая означает, что это удваивает используемую память.Это можно улучшить, используя itertools.islice, который возвращает итератор (и, следовательно, использует только постоянную память).Например, вторая версия будет выглядеть так:

def word_index(phrase):
  char_pairs = zip(phrase, itertools.islice(phrase, 1, None))
  new_words = map(lambda p: int(p[0] == " " and p[1] != " "), char_pairs)
  return itertools.accumulate(new_words)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...