计算单词列表中的字母频率,不包括同一单词中的重复项

Mat*_*eek 41 python algorithm

我想在一个单词列表中找到最常见的字母.我正在努力学习这个算法,因为我只需要在跳过重复项时只计算一个单词中的字母频率,所以我需要帮助找到一种方法来计算整个列表中字母的频率,每个单词只出现一次,忽略了第二次出现.

例如,如果我有:

words = ["tree", "bone", "indigo", "developer"]
Run Code Online (Sandbox Code Playgroud)

频率将是:

letters={a:0, b:1, c:0, d:2, e:3, f:0, g:1, h:0, i:1, j:0, k:0, l:1, m:0, n:2, o:3, p:1, q:0, r:2, s:0, t:1, u:0, v:1, w:0, x:0, y:0, z:0}
Run Code Online (Sandbox Code Playgroud)

从字母词典中可以看出:'e'是3而不是5,因为如果'e'在同一个单词中重复多次,则应忽略它.

这是我提出的算法,它是用Python实现的:

for word in words:
    count=0;

    for letter in word:
        if(letter.isalpha()):
            if((letters[letter.lower()] > 0  && count == 0) ||
               (letters[letter.lower()] == 0 && count == 0)):

                    letters[letter.lower()]+=1
                    count=1

            elif(letters[letter.lower()]==0 && count==1):   
                letters[letter.lower()]+=1
Run Code Online (Sandbox Code Playgroud)

但它仍然需要工作,我无法想到任何其他事情,我会很高兴有人帮我思考一个有效的解决方案.

Dan*_*ejo 57

@Primusa的变体在不使用更新的情况下回答:

from collections import Counter

words = ["tree", "bone", "indigo", "developer"]
counts = Counter(c for word in words for c in set(word.lower()) if c.isalpha())
Run Code Online (Sandbox Code Playgroud)

产量

Counter({'e': 3, 'o': 3, 'r': 2, 'd': 2, 'n': 2, 'p': 1, 'i': 1, 'b': 1, 'v': 1, 'g': 1, 'l': 1, 't': 1})
Run Code Online (Sandbox Code Playgroud)

基本上将每个单词转换为一个集合,然后迭代每个集合.


Pri*_*usa 18

创建一个计数器对象,然后使用每个单词的集合更新它:

from collections import Counter

wordlist = ["tree","bone","indigo","developer"]

c = Counter()
for word in wordlist:
    c.update(set(word.lower()))

print(c)
Run Code Online (Sandbox Code Playgroud)

输出:

Counter({'e': 3, 'o': 3, 'r': 2, 'n': 2, 'd': 2, 't': 1, 'b': 1, 'i': 1, 'g': 1, 'v': 1, 'p': 1, 'l': 1})
Run Code Online (Sandbox Code Playgroud)

需要注意的是,虽然是没有出现在信件wordlist没有在本中Counter,这是很好的,因为一个Counter表现得像defaultdict(int),所以访问没有自动显示数值返回默认值0.

  • 将该解决方案的时间复杂度与OP提供的时间复杂度进行比较将是有帮助的 (2认同)
  • @JordanSinger我认为它们是同一时间的复杂性,两种解决方案都会迭代每个单词中的每个字符; 我只是使用`set`来筛选重复项 (2认同)

mad*_*ad_ 15

一个没有柜台

words=["tree","bone","indigo","developer"]
d={}
for word in words:         # iterate over words
    for i in set(word):    # to remove the duplication of characters within word
        d[i]=d.get(i,0)+1
Run Code Online (Sandbox Code Playgroud)

产量

{'b': 1,
 'd': 2,
 'e': 3,
 'g': 1,
 'i': 1,
 'l': 1,
 'n': 2,
 'o': 3,
 'p': 1,
 'r': 2,
 't': 1,
 'v': 1}
Run Code Online (Sandbox Code Playgroud)


Ral*_*alf 11

比较目前提供的解决方案的速度:

def f1(words):
    c = Counter()
    for word in words:
        c.update(set(word.lower()))
    return c

def f2(words):
    return Counter(
        c
        for word in words
        for c in set(word.lower()))

def f3(words):
    d = {}
    for word in words:
        for i in set(word.lower()):
            d[i] = d.get(i, 0) + 1
    return d
Run Code Online (Sandbox Code Playgroud)

我的计时功能(使用不同大小的单词列表):

word_list = [
    'tree', 'bone', 'indigo', 'developer', 'python',
    'language', 'timeit', 'xerox', 'printer', 'offset',
]

for exp in range(5):
    words = word_list * 10**exp

    result_list = []
    for i in range(1, 4):
        t = timeit.timeit(
            'f(words)',
            'from __main__ import words,  f{} as f'.format(i),
            number=100)
        result_list.append((i, t))

    print('{:10,d} words | {}'.format(
        len(words),
        ' | '.join(
            'f{} {:8.4f} sec'.format(i, t) for i, t in result_list)))
Run Code Online (Sandbox Code Playgroud)

结果:

        10 words | f1   0.0028 sec | f2   0.0012 sec | f3   0.0011 sec
       100 words | f1   0.0245 sec | f2   0.0082 sec | f3   0.0113 sec
     1,000 words | f1   0.2450 sec | f2   0.0812 sec | f3   0.1134 sec
    10,000 words | f1   2.4601 sec | f2   0.8113 sec | f3   1.1335 sec
   100,000 words | f1  24.4195 sec | f2   8.1828 sec | f3  11.2167 sec
Run Code Online (Sandbox Code Playgroud)

Counter与列表理解(这里f2())似乎是最快的.使用counter.update()似乎是一个慢点(在这里f1()).