我有一个 dict
有字符串型键,其确切值我不知道(因为它们是在其他地方动态生成的)。但是,我知道我想要的密钥包含一个特定的子字符串,并且具有此子字符串的单个密钥肯定在dict中。
检索此密钥的值的最佳或“最pythonic”方法是什么?
我想到了两个策略,但两个都让我感到烦恼:
for k,v in some_dict.items():
if 'substring' in k:
value = v
break
- 要么 -
value = [v for (k,v) in some_dict.items() if 'substring' in k][0]
第一种方法是笨重而有些丑陋,而第二种方法更清洁,但是进入列表理解的额外步骤( [0]
)让我烦恼。是否有更好的方式来表达第二个版本,或者更简洁的方式来编写第一个版本?
可以选择使用第一个版本的性能属性编写第二个版本。
用一个 发电机表达 而不是列表理解:
value = next(v for (k,v) in some_dict.iteritems() if 'substring' in k)
括号内的表达式将返回一个迭代器,然后您将要求它提供下一个,即第一个元素。没有处理其他元素。
这个怎么样:
value = (v for (k,v) in some_dict.iteritems() if 'substring' in k).next()
它会在找到第一场比赛时立即停止。
但它仍然具有O(n)复杂度,其中n是键值对的数量。您需要类似后缀列表或后缀树的内容来加快搜索速度。
如果有很多键但字符串很容易从子字符串重构,那么它可以更快地重建它。例如通常你知道密钥的开头但不知道附加的日期戳。 (因此,您可能只需要尝试365个日期,而不是迭代数百万个密钥)。
情况不太可能如此,但我认为无论如何我会建议它。
例如
>>> names={'bob_k':32,'james_r':443,'sarah_p':12}
>>> firstname='james' #you know the substring james because you have a list of firstnames
>>> for c in "abcdefghijklmnopqrstuvwxyz":
... name="%s_%s"%(firstname,c)
... if name in names:
... print name
...
james_r
class MyDict(dict):
def __init__(self, *kwargs):
dict.__init__(self, *kwargs)
def __getitem__(self,x):
return next(v for (k,v) in self.iteritems() if x in k)
# Defining several dicos ----------------------------------------------------
some_dict = {'abc4589':4578,'abc7812':798,'kjuy45763':1002}
another_dict = {'boumboum14':'WSZE x478',
'tagada4783':'ocean11',
'maracuna102455':None}
still_another = {12:'jfg',45:'klsjgf'}
# Selecting the dicos whose __getitem__ method will be changed -------------
name,obj = None,None
selected_dicos = [ (name,obj) for (name,obj) in globals().iteritems()
if type(obj)==dict
and all(type(x)==str for x in obj.iterkeys())]
print 'names of selected_dicos ==',[ name for (name,obj) in selected_dicos]
# Transforming the selected dicos in instances of class MyDict -----------
for k,v in selected_dicos:
globals()[k] = MyDict(v)
# Exemple of getting a value ---------------------------------------------
print "some_dict['7812'] ==",some_dict['7812']
结果
names of selected_dicos == ['another_dict', 'some_dict']
some_dict['7812'] == 798
我更喜欢第一个版本,虽然我会使用 some_dict.iteritems()
(如果你使用的是Python 2)因为那时你不必事先建立所有项目的完整列表。相反,你会在完成后迭代dict并中断。
在Python 3上, some_dict.items(2)
已经导致字典视图,所以它已经是一个合适的迭代器。