如何有效地计算字符串中字符频率的前缀和?

时间:2019-04-29 13:15:12

标签: python python-3.x string

说,我有一个字符串

s = 'AAABBBCAB'

如何有效地计算字符串中每个字符的频率前缀总和,即:

psum = [{'A': 1}, {'A': 2}, {'A': 3}, {'A': 3, 'B': 1}, {'A': 3, 'B': 2}, {'A': 3, 'B': 3}, {'A': 3, 'B': 3, 'C': 1}, {'A': 4, 'B': 3, 'C': 1}, {'A': 4, 'B': 4, 'C': 1}]

5 个答案:

答案 0 :(得分:17)

这是一个选择:

from collections import Counter

c = Counter()
s = 'AAABBBCAB'

psum = []
for char in s:
    c[char] +=1
    psum.append(dict(c))

# [{'A': 1}, {'A': 2}, {'A': 3}, {'A': 3, 'B': 1}, {'A': 3, 'B': 2}, 
#  {'A': 3, 'B': 3}, {'A': 3, 'B': 3, 'C': 1}, {'A': 4, 'B': 3, 'C': 1},
#  {'A': 4, 'B': 4, 'C': 1}]

我使用collections.Counter来保持“运行总和”,并将(结果的副本)添加到列表psum中。这样,我仅对字符串s进行一次迭代。


仅出于完整性考虑(因为此处没有“纯dict”的答案)。如果您不想使用Counterdefaultdict,也可以使用:

c = {}
s = 'AAABBBCAB'

psum = []
for char in s:
    c[char] = c.get(char, 0) + 1
    psum.append(c.copy())

尽管defaultdict的性能通常比dict.get(key, default)高。

答案 1 :(得分:17)

您可以使用itertools.accumulatecollections.Counter在一行中完成此操作:

from collections import Counter
from itertools import accumulate

s = 'AAABBBCAB'
psum = list(accumulate(map(Counter, s)))

这将为您提供Counter对象的列表。现在,要获得O(1)时间内s的任何子字符串的频率,您可以简单地减去计数器,例如:

>>> psum[6] - psum[1]  # get frequencies for s[2:7]
Counter({'B': 3, 'A': 1, 'C': 1})

答案 2 :(得分:6)

最简单的方法是使用集合中的Counter对象。

from collections import Counter

s = 'AAABBBCAB'

[ dict(Counter(s[:i]) for i in range(1,len(s))]

收益:

[{'A': 1},  {'A': 2},  {'A': 3},  {'A': 3, 'B': 1},  {'A': 3, 'B': 2},
{'A': 3, 'B': 3},  {'A': 3, 'B': 3, 'C': 1},  {'A': 4, 'B': 3, 'C': 1}]

答案 3 :(得分:4)

您实际上甚至不需要计数器,只需一个defaultdict就足够了!

from collections import defaultdict

c = defaultdict(int)
s = 'AAABBBCAB'

psum = []

#iterate through the character
for char in s:
    #Update count for each character
    c[char] +=1
    #Add the updated dictionary to the output list
    psum.append(dict(c))

print(psum)

输出看起来像

[{'A': 1}, {'A': 2}, {'A': 3}, {'A': 3, 'B': 1}, 
{'A': 3, 'B': 2}, {'A': 3, 'B': 3}, 
{'A': 3, 'B': 3, 'C': 1}, {'A': 4, 'B': 3, 'C': 1}, 
{'A': 4, 'B': 4, 'C': 1}]

答案 4 :(得分:1)

在Python 3.8中,您可以将列表理解与assignment expression(也称为“海象运算符”)一起使用:

>>> from collections import Counter
>>> s = 'AAABBBCAB'
>>> c = Counter()
>>> [c := c + Counter(x) for x in s]
[Counter({'A': 1}), Counter({'A': 2}), Counter({'A': 3}), Counter({'A': 3, 'B': 1}), Counter({'A': 3, 'B': 2}), Counter({'A': 3, 'B': 3}), Counter({'A': 3, 'B': 3, 'C': 1}), Counter({'A': 4, 'B': 3, 'C': 1}), Counter({'A': 4, 'B': 4, 'C': 1})]