用他们的单词索引替换字符串字符



请注意此字符串中的两个连续空间:

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并不遥远。也许您可以使用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循环来做同样的事情,但是我不确定它不会混淆代码(请参阅Python Zen的第三个项目)。这是它的外观,请注意,我在这里使用了lambda功能,不是因为我认为这是最好的选择,而是因为我找不到任何有意义的函数名称:

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)

最新更新