簡體   English   中英

如何有效計算字符串中字符出現頻率的前綴和?

[英]How to efficiently calculate prefix sum of frequencies of characters in a 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}]

您可以使用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})

這是一個選項:

from collections import Counter

c = Counter()
s = 'AAABBBCAB'

psum = []
for char in s:
    c.update(char)
    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迭代一次。

如果您希望在結果中包含collections.Counter對象,則可以將最后一行更改為

psum.append(c.copy())

為了得到

[Counter({'A': 1}), Counter({'A': 2}), ...
 Counter({'A': 4, 'B': 4, 'C': 1})]

同樣的結果也可以通過這個來實現(使用accumulate首先在Eugene Yarmash的答案中提出;我只是避免使用map來支持生成器表達式):

from itertools import accumulate
from collections import Counter

s = "AAABBBCAB"
psum = list(accumulate(Counter(char) for char in 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)dict.get(key, default)

最簡單的方法是使用集合中的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}]

你實際上甚至不需要一個計數器,只需一個默認就足夠了!

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}]

在Python 3.8中,您可以使用帶有賦值表達式的列表推導(也稱為“海象運算符”):

>>> 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})]

試試這個:

>>> s = 'AAABBBCAB'
>>> res = [{letter_: s[0:i+1].count(letter_) for letter_ in set(s[0:i+1])} for i in range(len(s))]
>>> res
[{'A': 1}, {'A': 2}, {'A': 3}, {'B': 1, 'A': 3}, {'B': 2, 'A': 3}, {'B': 3, 'A': 3}, {'B': 3, 'C': 1, 'A': 3}, {'B': 3, 'C': 1, 'A': 4}, {'B': 4, 'C': 1, 'A': 4}]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM