我正在解析一些xml(带有一些python 3.4代码),并希望从节点及其id属性中检索文本。例:
<li id="12345"> Some text here </li>
我当前的代码仅围绕文本构建(我现在添加了id,但之前并不需要这个)。我循环浏览一个文本/句子列表,然后继续做一些事情。所以我想创建一个以文本/句子为键的字典,并将此id属性作为值。
然而,这并不是非常有效。文本可以是整个段落,使得密钥很长。而id总是相当有限的长度(但仍然是str类型,例如一些字母字符后跟一些数字)。 但是,使id成为键,文本值需要对代码进行一些重写。所有这些都不是很有问题,但这让我感到疑惑:将文本(可能是整个段落)作为关键词的效率是多么低效,与像#&lt;&#34; ulp_887362487687678&#34;作为关键?
我可以制作两个反向词典(一个以id作为键,另一个以text作为键)并比较构造和查找以及所有。我还发现了关键长度限制(Do Dictionaries have a key length limit?)的一些主题。但我只是想知道你对此有何看法。在你的词典中有这么长的str键你肯定想要避免,或者这不是一个大问题? 如果你可以分享一些专业人士,那就太棒了!
答案 0 :(得分:11)
不,Python字符串长度几乎不会对字典性能产生影响。字符串长度唯一可能影响的是hash()
函数,它将键映射到哈希表槽。
字符串长度对hash()
的性能影响很小:
>>> import random
>>> from timeit import timeit
>>> from string import ascii_letters
>>> generate_text = lambda len: ''.join([random.choice(ascii_letters) for _ in xrange(len)])
>>> for i in range(8):
... length = 10 + 10 ** i
... testword = generate_text(length)
... timing = timeit('hash(t)', 'from __main__ import testword as t')
... print 'Length: {}, timing: {}'.format(length, timing)
...
Length: 11, timing: 0.061537027359
Length: 20, timing: 0.0796310901642
Length: 110, timing: 0.0631730556488
Length: 1010, timing: 0.0606122016907
Length: 10010, timing: 0.0613977909088
Length: 100010, timing: 0.0607581138611
Length: 1000010, timing: 0.0672461986542
Length: 10000010, timing: 0.080118894577
我停止生成一个包含1000万个字符的字符串,因为我无法等待笔记本电脑生成1亿个字符串。
时间几乎是不变的,因为一旦计算出来,该值实际上会缓存在字符串对象上。
答案 1 :(得分:1)
对于字符串,hash()
的性能确实为O(n)
,但结果缓存在字符串中-重复调用将使用缓存的值。这是可能的,因为字符串是不可变的。 Martijn的代码使用timeit
的 repeating 功能,因此您看不到这种效果,因为在最后一种情况下,在10000010中,没有10000009次计算哈希码。
下面仍然是(大约)O(n)
import random
from timeit import timeit
for i in range(10):
length = 10 ** i
# notice number=1 !!!
timing = timeit('hash(t)', 't = "a" * {}'.format(length), number=1)
print('Length: {:10d}, timing: {:.20f}'.format(length, timing))
Length: 1, timing: 0.00000437500057159923
Length: 10, timing: 0.00000287900184048340
Length: 100, timing: 0.00000342299972544424
Length: 1000, timing: 0.00000459299917565659
Length: 10000, timing: 0.00002153400055249222
Length: 100000, timing: 0.00006719700104440562
Length: 1000000, timing: 0.00066680999952950515
Length: 10000000, timing: 0.00673243699930026196
Length: 100000000, timing: 0.04393487600100343116
Length: 1000000000, timing: 0.39340837700001429766
差异是由于时序错误,分支预测等所致。
答案 2 :(得分:0)
在大多数情况下,@ Martijn Pieters的回答是正确的,即从理论上讲。 但是,实际上,在性能方面您要考虑很多事情。
我最近遇到了将长字符串散列为键的问题,并且由于python的字典键散列,我在练习中遇到了超时错误。我知道这一点是因为我使用JavaScript对象作为“字典”解决了这个问题,并且效果很好,这意味着没有超时错误。
然后,因为我的键实际上是一长串数字列表,所以我改为使它们成为数字元组(不可变对象可以是键)。那也很好。
话虽这么说,我使用示例中编写的哈希函数@Martijn Pieters和一长串数字列表作为元组版本的键来测试了计时。 tuples版本花费更长的时间在其python编译器repl.it上。我说的不是0.1差异。这是0.02和12.02之间的差异。
是不是很奇怪?! :>
现在要指出的是,每个环境都不同。您的操作量不断累积。因此,您不能简单地说出某些操作将花费更长或更短的时间。即使是0.01秒的操作,也只能执行1000次,使用户等待10秒。
对于任何生产环境,如果需要,您确实想尝试优化算法,并始终使用更好的设计。对于普通软件,它可以节省用户的宝贵时间。对于云服务,这将是我们正在谈论的钞票。
最后,我绝对请勿建议仅将长字符串用作键,因为我在不同环境中得到的结果不一致。您绝对希望将id用作键,并在需要时遍历字符串值以查找id。但是,如果必须将长字符串用作键,请考虑限制字典上的操作数。保留两个版本绝对是浪费空间/ RAM。性能和内存主题是另一堂课。