计算后续字母

Counting subsequent letters

所以我正在尝试使用 python 实现计算句子中下一个字母的代码。 例如,

"""So I am trying to implement code that will count the next letter in a sentence, using 
python"""

最常用的字母一个接一个

  1. 为's'

    • 'o' :1
    • 'e' :1
  2. 对于'o'

    • ' ':1
    • 'd' :1
    • 'u' :1
    • 'n' :1

我想你明白了

我已经编写了计算字母数的代码

def count_letters(word, char):
    count = 0
    for c in word:
        if char == c:
            count += 1
    return count

如您所见,这只计算字母,而不计算下一个字母。有人可以帮助我解决这个问题吗?

下面是使用 collections.Counter 的方法:

假设您提供的字符串存储在变量 s 中。

首先我们遍历 s 中所有小写字母的集合。我们通过创建另一个字符串 s_lower 来完成此操作,它将字符串 s 转换为小写。然后我们用 set 构造函数包装它以获得唯一值。

对于每个 char,我们遍历字符串并检查前一个字母是否等于 char。如果是这样,我们将其存储在列表中。最后,我们将这个列表传递给 collections.Counter 构造函数,它将计算出现次数。

每个计数器都存储在字典中,counts,其中键是字符串中的唯一字符。

from collections import Counter

counts = {}
s_lower = s.lower()
for char in set(s_lower):
    counts[char] = Counter(
        [c for i, c in enumerate(s_lower) if i > 0 and s_lower[i-1] == char]
    )

对于您的字符串,它有以下输出:

>>> print(counts['s'])
#Counter({'i': 1, 'e': 1, 'o': 1})

>>> print(counts['o'])
#Counter({' ': 2, 'd': 1, 'n': 1, 'u': 1})

需要注意的是,此方法将为每个唯一字符遍历整个字符串,这可能会使大型列表变慢。


这是使用 collections.Countercollections.defaultdict 的替代方法,它只循环一次字符串:

from collections import defaultdict, Counter

def count_letters(s):
    s_lower = s.lower()
    counts = defaultdict(Counter)
    for i in range(len(s_lower) - 1):
        curr_char = s_lower[i]
        next_char = s_lower[i+1]
        counts[curr_char].update(next_char)
    return counts

counts = count_letters(s)

我们遍历字符串中的每个字符(最后一个字符除外),并在每次迭代中使用下一个字符更新计数器。

from collections import Counter, defaultdict

counts = defaultdict(Counter)

s = """So I am trying to implement code that will count the next letter in a sentence, using
python""".lower()

for c1, c2 in zip(s, s[1:]):
    counts[c1][c2] += 1

(除了更简单之外,这应该比 pault 的答案快得多,因为它不会为每个字母遍历字符串)

代码中未命名的 google 概念:

  • for c1, c2 in ...(即有两个变量的事实):元组解包
  • s[1:]:切片。基本上这是第一个字符后字符串的副本。

这里有一个相对简洁的方法:

from itertools import groupby
from collections import Counter

def countTransitionFrequencies(text):
  prevNext = list(zip(text[:-1], text[1:]))
  prevNext.sort(key = lambda pn: pn[0])
  transitions = groupby(prevNext, lambda pn: pn[0])
  freqs = map(
    lambda kts: (kts[0], Counter(map(lambda kv: kv[1], kts[1]))), 
    transitions
  )
  return freqs

解释:

  1. zip 创建具有 (previous, next) 个字符的对列表
  2. 这些对按 previous 字符排序和分组
  3. 然后使用 Counter.
  4. 计算 next 个字符的频率(由 kv[1] 从对中提取)

排序并不是真正必要的,但不幸的是,这就是所提供的 groupby 的工作方式。

一个例子:

for k, v in countTransitionFrequencies("hello world"):
  print("%r -> %r" % (k, v))

这会打印:

' ' -> Counter({'w': 1})
'e' -> Counter({'l': 1})
'h' -> Counter({'e': 1})
'l' -> Counter({'l': 1, 'o': 1, 'd': 1})
'o' -> Counter({' ': 1, 'r': 1})
'r' -> Counter({'l': 1})
'w' -> Counter({'o': 1})

这应该可行,唯一的问题是它不对值进行排序,但这可以通过创建一个包含元组列表 (char, occurrences) 的新字典并在元组 [1] 上使用排序函数来解决。

def countNext(word):
    d = {}
    word = word.lower()
    for i in range(len(word) - 1):
        c = word[i]
        cc = word[i+1]
        if(not c.isalpha() or not cc.isalpha()):
            continue
        if c in d:
            if cc in d[c]:
                d[c][cc] += 1
            else:
                d[c][cc] = 1
        else:
            d[c] = {}
            d[c][cc] = 1
    return d