【问题标题】:Counting subsequent letters计算后续字母
【发布时间】:2018-09-09 20:02:01
【问题描述】:

所以我正在尝试使用 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
    • '你':1
    • 'n' :1

我想你明白了

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

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

如您所见,这仅计算字母,但不计算下一个字母。有人可以帮我看看这个吗?

【问题讨论】:

标签: python string frequency letter frequency-distribution


【解决方案1】:

这是一种使用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)

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

【讨论】:

  • 第一个测试用例应该是Counter({'o': 1, 'e': 1, 'i': 1})。你错过了'o'
  • 也可以是set(map(str.lower, s)) set(s.lower())
  • @AlexHall 很好。我忘记了一个.lower()。现已编辑。关于set(s.lower() 也很好。
  • 那么,它会在整个文本中运行数十甚至数百次吗?每个角色一次?
  • @AndreyTyukin 我没说这是最好的解决方案。
【解决方案2】:
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 的答案要快得多,因为它不对每个字母都遍历字符串)

未在代码中命名的谷歌概念:

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

【讨论】:

【解决方案3】:

这是一个相对简洁的方法:

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 计算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})

【讨论】:

    【解决方案4】:

    这应该可行,唯一的问题是它不对值进行排序,但这可以通过创建一个包含元组列表(字符、出现次数)的新字典并在元组 [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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-20
      • 1970-01-01
      • 1970-01-01
      • 2019-04-30
      • 1970-01-01
      • 2019-08-14
      • 1970-01-01
      • 2017-03-12
      相关资源
      最近更新 更多