将列表元素与其索引相关联的pythonic方法

Posted

技术标签:

【中文标题】将列表元素与其索引相关联的pythonic方法【英文标题】:pythonic way to associate list elements with their indices 【发布时间】:2011-02-19 08:58:55 【问题描述】:

我有一个值列表,我想将它们放在一个字典中,该字典会将每个值映射到它的索引。

我可以这样做:

>>> t = (5,6,7)
>>> d = dict(zip(t, range(len(t))))
>>> d
5: 0, 6: 1, 7: 2

这还不错,但我正在寻找更优雅的东西。

我遇到了以下情况,但这与我需要的相反:

>>> d = dict(enumerate(t))
>>> d
0: 5, 1: 6, 2: 7

请分享您的解决方案, 谢谢

编辑:Python 2.6.4

对于包含 1000 个元素的列表,dict(zip) 版本是最快的,生成器和列表理解版本几乎相同,它们慢了约 1.5 倍,而功能映射(反转)则慢得多。

$ python -mtimeit -s"t = range(int(1e3))" "d = dict(zip(t, range(len(t))))" 1000 个循环,最好的 3 个:每个循环 277 微秒

$ python -mtimeit -s"t = range(int(1e3))" "d = dict([(y,x) for x,y in enumerate(t)])" 1000 个循环,最好的 3 个:每个循环 426 微秒

$ python -mtimeit -s"t = range(int(1e3))" "d = dict((y,x) for x,y in enumerate(t))" 1000 个循环,最好的 3 个:每个循环 437 微秒

$ python -mtimeit -s"t = range(int(1e3))" "d = dict(map(reversed, enumerate(t)))" 100 个循环,3 个循环中的最佳:每个循环 3.66 毫秒

我尝试对更长和更短的列表(1e2、1e4、1e5)运行相同的测试,每个循环的时间与列表的长度成线性关系。

有人可以给 py 2.7+ 版本计时吗?

【问题讨论】:

我很好奇 - 哪个实现更快?顺便问一下,Chewy,你用的是哪个版本的 Python? 【参考方案1】:

您可以使用列表推导式(或生成器,具体取决于您的 python 版本)为您的第二个示例执行简单的就地交换。


使用列表推导:

d = dict([(y,x) for x,y in enumerate(t)])

使用生成器表达式(Python 2.4 及更高版本):

d = dict((y,x) for x,y in enumerate(t))

【讨论】:

那里不需要[]dict 可以很好地与生成器表达式配合使用(保存生成中间列表) 是的,这就是我写“取决于你的 python 版本”的原因。生成器已经存在了很长时间(从 2.4 开始),所以我将两者都包括在内 @J.F. Sebastian 在 2004 年之前开发的部署系统中? Python 已经存在了很长一段时间了。不难想象必须在一些 Python 2.0 应用程序上工作,我的意思是有些人仍然必须在 VB6 中工作。【参考方案2】:

在Python2.7+可以这样写

>>> t = (5,6,7)
>>> d = x:i for i,x in enumerate(t)
>>> print d
5: 0, 6: 1, 7: 2

【讨论】:

【参考方案3】:
>>> dict((x,i) for i,x in enumerate(t))
5: 0, 6: 1, 7: 2
>>>

【讨论】:

【参考方案4】:

您的所有元素都是独一无二的吗(即您的列表永远不会是 5、6、7、7)? dict 解决方案仅在您的所有元素都是唯一的情况下才有效。

通过存储索引,您实际上是在复制信息,因为您可以简单地查询列表中项目的当前索引。复制信息通常不是最好的主意,因为它可能会导致一组数据与另一组数据不同步。

如果正在修改列表,也没有什么可以阻止您不小心将同一索引分配给多个项目。

当您可以简单地从列表中获取索引时,您为什么要尝试存储索引值?

【讨论】:

所有列表元素都是唯一的。我将索引存储在不同的数据结构中以便快速查找。 如果所有元素都是唯一的,这听起来像是一个无用的间接级别,使用in 测试成员资格并使用index() 进行索引。我猜你认为哈希映射支持的字典会给你比index() 更快的查找速度。在 Python 中,过早优化确实是邪恶的,因为您对“更快”的直觉通常是错误的,直到实际计时。让它工作,然后找出你慢的地方,增加复杂性是不值得的。 @Dragan,您是在修改列表还是保持静态? @msw 有效的关注,总的来说我同意你,在这种情况下我认为这是值得的 python -mtimeit -s"t = range(int(1e2))" "truthVal = (55 in t)" # 3.11 usec per loop python -mtimeit -s"t = range(int(1e2)); d = dict(zip(t, range(len(t))))" "truthVal = (55 in d )" #0.138 usec per loop python -mtimeit -s"t = range(int(1e2))" "idxVal = t.index(55)" #3.46 usec per loop python -mtimeit -s"t = range(int( 1e2)); d = dict(zip(t, range(len(t))))" "indexVal = d[55]" #0.136 usec per loop @dragan:断言得到证实,即使我使用“5”作为目标,使您的测试严重偏向字典,但仍然以 3 到 7 倍的速度将门从列表中炸开。我认为缓存命中/未命中可能令人困惑,即使列表大小为 1e7 迫使它进行交换,它似乎也不适合我的系统。 (Python 2.6.5 Linux 2.6)【参考方案5】:

正如大家已经写过的,在 Python 2.6 中,我认为以下是最 Python 的:

>>> dict((x, i) for i, x in enumerate(t))
5: 0, 6: 1, 7: 2

不过,在功能***的时刻,我会写:

>>> dict(map(reversed, enumerate(t)))
5: 0, 6: 1, 7: 2

【讨论】:

【参考方案6】:

我最喜欢 dict(zip(t, range(len(t))))。

【讨论】:

以上是关于将列表元素与其索引相关联的pythonic方法的主要内容,如果未能解决你的问题,请参考以下文章

在Python中查找与数据框元素列表相对应的索引列表

数据结构学习--单链表(python)

Python数据类型

将 aiohttp 请求与其响应相关联

如何将每个选项按钮与其各自的标记相关联?

如何将 WAVE_MAPPER 音频线与其音频设备相关联