关于将列表转换为词典,我遇到了一些速度问题,其中以下操作占总运行时间的90%左右:
def list2dict(list_):
return_dict = {}
for idx, word in enumerate(list_):
if word in return_dict:
raise ValueError("duplicate string found in list: %s" % (word))
return_dict[word] = idx
return return_dict
我很难看到导致这种情况的原因。您是否在代码中看到了明显的瓶颈,或者有关如何加快速度的建议?
感谢。
答案 0 :(得分:1)
编辑:
想象一下,我把它放在首位,因为它更大 - 事实证明,对OP的代码进行微小的调整会给性能带来很大的影响。
def list2dict(list_): # OLD
return_dict = {}
for idx, word in enumerate(list_):
if word in return_dict: # this compare is happening every iteration!
raise ValueError("duplicate string found in list: %s" % (word))
return_dict[word] = idx
return return_dict
def list2dictNEW(list_): #NEW HOTNESS
return_dict = {}
for idx, word in enumerate(list_):
return_dict[word] = idx # overwrite if you want to, because...
if len(return_dict) == len(list_): return return_dict
# if the lengths aren't the same, something got overwritten so we
# won't return. If they ARE the same, toss it back with only one
# compare (rather than n compares in the original
else: raise ValueError("There were duplicates in list {}".format(list_))
DEMO:
>>> timeit(lambda: list2dictNEW(TEST))
1.9117132451798682
>>> timeit(lambda: list2dict(TEST)):
2.2543816669587216
# gains of a third of a second per million iterations!
# that's a 15.2% speed bost
没有明显的答案,但你可以尝试类似的东西:
def list2dict(list_):
return_dict = dict()
for idx,word in enumerate(list_):
return_dict.setdefault(word,idx)
return return_dict
您也可以构建一个集合并执行list.index
,因为您说列表相当小,但我认为这样会更慢而不是更快。这需要进行分析才能确定(使用timeit.timeit
)
def list2dict(list_):
set_ = set(list_)
return {word:list_.index(word) for word in set_}
我冒昧地在一组测试数据上运行一些配置文件。结果如下:
TEST = ['a','b','c','d','e','f','g','h','i','j'] # 10 items
def list2dictA(list_): # build set and index word
set_ = set(list_)
return {word:list_.index(word) for word in set_}
def list2dictB(list_): # setdefault over enumerate(list)
return_dict = dict()
for idx,word in enumerate(list_):
return_dict.setdefault(word,idx)
return return_dict
def list2dictC(list_): # dict comp over enumerate(list)
return_dict = {word:idx for idx,word in enumerate(list_)}
if len(return_dict) == len(list_):
return return_dict
else:
raise ValueError("Duplicate string found in list")
def list2dictD(list_): # Original example from Question
return_dict = {}
for idx, word in enumerate(list_):
if word in return_dict:
raise ValueError("duplicate string found in list: %s" % (word))
return_dict[word] = idx
return return_dict
>>> timeit(lambda: list2dictA(TEST))
5.336584700190931
>>> timeit(lambda: list2dictB(TEST))
2.7587691306531
>>> timeit(lambda: list2dictC(TEST))
2.1609074989233292
>>> timeit(lambda: list2dictD(TEST))
2.2543816669587216
答案 1 :(得分:1)
最快的功能取决于list_
的长度。对于小型列表(少于约80项),adsmith的list2dictC()
非常快。但是当列表大小增加时,我发现list2dictE()
的速度提高了约8%。
def list2dictC(list_): # dict comp over enumerate(list)
return_dict = {word: idx for idx, word in enumerate(list_)}
if len(return_dict) == len(list_):
return return_dict
else:
raise ValueError("Duplicate string found in list")
def list2dictE(list_): # Faster for lists with ~80 items or more
l = len(list_)
return_dict = dict(zip(list_, range(l)))
if len(return_dict) == l:
return return_dict
else:
raise ValueError("Duplicate string found in list")
如果已知长度很小,则保持它没有用,但如果不是这样,可能会添加l = len(list_); if l < 80: ... else: ...
之类的东西。它只是一个额外的if语句,因为两个函数都需要知道列表长度。 80个项目的门槛可能很大程度上取决于你的设置,但对于我来说,这对于我来说都是python 2.7和3.3。
答案 2 :(得分:0)
def l2d(list_):
dupes = set(filter(lambda x: a.count(x) > 1, a))
if len(dupes) > 0:
raise ValueError('duplicates: %s' % (dupes))
return dict((word, idx) for (idx, word) in enumerate(list_))
这是如何比较的?
答案 3 :(得分:0)
使用熊猫似乎加速了三分之一,尽管据说它已经“足够快”了
> TEST = # english scrabble dictionary, 83882 entries
> def mylist2dict(list_):
return_dict = pd.Series(index=list_, data=np.arange(len(list_)))
if not return_dict.index.is_unique:
raise ValueError
return return_dict
> %timeit list2dict(TEST)
10 loops, best of 3: 28.8 ms per loop
> %timeit mylist2dict(TEST)
100 loops, best of 3: 18.8 ms per loop
答案 4 :(得分:0)
每次运行的平均值为2.36μs。因为OPs代码看起来像是支持第一个值的事件,所以我颠倒了范围,因此它不需要任何逻辑来检查值是否存在。
def mkdct(dct):
l = len(dct-1)
return {dct[x]:(l-x) for x in range(len(dct), -1, -1)}
编辑:那里有一些愚蠢的错误。