我试图在字典中存储给定字母在另一个给定字母后出现的次数。例如,dictionary['a']['d']
会在'd'
中给出'a'
short_list
次alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
short_list = ['ford','hello','orange','apple']
# dictionary to keep track of how often a given letter occurs
tally = {}
for a in alphabet:
tally[a] = 0
# dictionary to keep track of how often a given letter occurs after a given letter
# e.g. how many times does 'd' follow 'a' -- master_dict['a']['d']
master_dict = {}
for a in alphabet:
master_dict[a] = tally
def precedingLetter(letter,word):
if word.index(letter) == 0:
return
else:
return word[word.index(letter)-1]
for a in alphabet:
for word in short_list:
for b in alphabet:
if precedingLetter(b,word) == a:
master_dict[a][b] += 1
次。
master_dict
但是,{{1}}中所有字母(键)的条目都是相同的。我无法想出另一种方法,可以在另一封信之后恰当地记录每封字母的出现。谁能在这里提供一些见解?
答案 0 :(得分:2)
如果子dict
都应该在创建后独立更新,则需要浅层复制它们。最简单/最快捷的方法是.copy()
:
for a in alphabet:
master_dict[a] = tally.copy()
另一种方法是懒惰地初始化dict
。最简单的方法是使用defaultdict
:
from collections import defaultdict
masterdict = defaultdict(lambda: defaultdict(int))
# or
from collections import Counter, defaultdict
masterdict = defaultdict(Counter)
根本不需要预先创建空的标签或填充masterdict
,这样可以避免在字母永远不会出现时创建dict
。如果您为masterdict[a]
访问尚不存在的a
,则会自动为其创建defaultdict(int)
值。访问masterdict[a][b]
但不存在时,计数会自动初始化为0
。
答案 1 :(得分:2)
除了第一个答案之外,以相反的方式执行搜索可能很方便。因此,不是寻找每对可能的字母,而是可以遍历单词。
结合defaultdict
,这可以简化流程。举个例子:
from collections import defaultdict
short_list = ['ford','hello','orange','apple']
master_dict = defaultdict(lambda: defaultdict(int))
for word in short_list:
for i in range(0,len(word)-1):
master_dict[word[i]][word[i+1]] += 1
现在master_dict
包含所有出现的字母组合,而对于所有其他字母组合则返回零。以下几个例子:
print(master_dict["f"]["o"]) # ==> 1
print(master_dict["o"]["r"]) # ==> 2
print(master_dict["a"]["a"]) # ==> 0
答案 2 :(得分:1)
你问的问题是master_dict[a] = tally
只是为同一个对象分配了另一个名字,所以通过任何引用更新它们都会更新它们。您可以通过使用master_dict[a] = tally.copy()
中已经指出的master_dict
每次复制它来解决此问题。
正如@ShadowRanger继续指出的那样,使defaultdict(lambda: defaultdict(int))
成为short_list
也会少得多浪费,因为这样做只会为实际遇到的组合分配和初始化计数而不是所有可能的2个字母排列(如果使用得当)。
为了让您对节省的音乐会有所了解,请考虑您的样本precedingLetter()
中只有15个独特的字母对,但详尽的方法仍然可以为所有676个字典创建和初始化26个字典中的26个占位符可能的数量。
在我看来,你真的根本不需要一个两级字典来完成你想要的东西,因为同一个字母可以用一个包含由字符对元组组成的键的字典来完成。
除此之外,正如@ShadowRanger's answer所指出的,另一个重要的改进是你通过from collections import defaultdict
from string import ascii_lowercase
alphabet = set(ascii_lowercase)
short_list = ['ford','hello','orange','apple']
# dictionary to keep track of how often a letter pair occurred after one other.
# e.g. how many times 'd' followed an 'a' -> master_dict[('a','d')]
master_dict = defaultdict(int)
try:
from itertools import izip
except ImportError: # Python 3
izip = zip
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = iter(iterable), iter(iterable) # 2 independent iterators
next(b, None) # advance the 2nd one
return izip(a, b)
for word in short_list:
for (ch1,ch2) in pairwise(word.lower()):
if ch1 in alphabet and ch2 in alphabet:
master_dict[(ch1,ch2)] += 1
# display results
unique_pairs = 0
for (ch1,ch2) in sorted(master_dict):
print('({},{}): {}'.format(ch1, ch2, master_dict[(ch1,ch2)]))
unique_pairs += 1
print('A total of {} different letter pairs occurred in'.format(unique_pairs))
print('the words: {}'.format(', '.join(repr(word) for word in short_list)))
函数迭代所有可能的排列并查看它们是否在每个单词中的方法是显着比你只是迭代在每一对中实际发生的所有连续字母对时更耗时。
因此,将所有这些建议放在一起会导致如下所示:
short_list
从(a,n): 1
(a,p): 1
(e,l): 1
(f,o): 1
(g,e): 1
(h,e): 1
(l,e): 1
(l,l): 1
(l,o): 1
(n,g): 1
(o,r): 2
(p,l): 1
(p,p): 1
(r,a): 1
(r,d): 1
A total of 15 different letter pairs occurred in
the words: 'ford', 'hello', 'orange', 'apple'
生成此输出:
{{1}}