请注意该字符串中两个连续的空格:
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语言,但是我想学习一种更Python化的方法来解决此问题。
答案 0 :(得分:1)
我觉得您的解决方案与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)))
这也利用了generators,这在python中很常见(请参阅yield
keyword的文档)。您可以使用itertools.accumulate
而不是for循环来执行相同的操作,但是我不确定它不会混淆代码(请参见The Zen of Python的第三项)。这就是它的样子,请注意,我在这里使用了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)
第二个版本类似于第一个版本,返回iterator。请注意,使用迭代器通常是一个好主意,因为它不会对用户是否要实例化任何内容做出任何假设。如果用户想将迭代器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)