我有一个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]
)让我感到烦恼。是否有更好的方式来表达第二个版本,或者更简洁的方式来编写第一个版本?
答案 0 :(得分:10)
可以选择使用第一个版本的性能属性编写第二个版本。
使用generator expression代替列表理解:
value = next(v for (k,v) in some_dict.iteritems() if 'substring' in k)
括号内的表达式将返回一个迭代器,然后您将要求它提供下一个,即第一个元素。没有其他元素被处理。
答案 1 :(得分:1)
这个怎么样:
value = (v for (k,v) in some_dict.iteritems() if 'substring' in k).next()
当它找到第一场比赛时会立即停止。
但它仍然具有O(n)复杂度,其中n是键值对的数量。你需要像后缀列表或后缀树这样的东西来加速搜索。
答案 2 :(得分:1)
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
答案 3 :(得分:1)
如果有很多键,但字符串很容易从子字符串重建,那么它可以更快地重建它。例如通常你知道密钥的开头但不知道附加的日期戳。 (因此,您可能只需要尝试365个日期,而不是迭代数百万个密钥)。 情况不太可能如此,但我认为无论如何我会建议它。 e.g。
>>> 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
答案 4 :(得分:0)
我更喜欢第一个版本,虽然我使用some_dict.iteritems()
(如果您使用的是Python 2),因为这样您就不必事先构建所有项目的完整列表。相反,你会在完成后迭代dict并中断。
在Python 3上,some_dict.items(2)
已经产生了字典视图,因此它已经是一个合适的迭代器。