python将列表转换为字典

Sha*_*kan 71 python dictionary list

l = ["a", "b", "c", "d", "e"]
Run Code Online (Sandbox Code Playgroud)

我想将此列表转换为如下字典:

d = {"a": "b", "c": "d", "e": ""}
Run Code Online (Sandbox Code Playgroud)

所以基本上,均衡将是关键,而赔率将是价值.我知道我可以用"非pythonic"的方式来实现它,例如if语句的for循环,但我相信应该有更"pythonic"的方法来实现这一点.所以,我感谢任何帮助:)

nic*_*kl- 140

如果你还在想什么!你不会孤单,它实际上并不那么复杂,让我解释一下.

如何仅使用内置函数将列表转换为字典

我们希望使用奇数条目(从1开始计数)将以下列表转换为字典,作为映射到其连续偶数条目的键.

l = ["a", "b", "c", "d", "e"]
Run Code Online (Sandbox Code Playgroud)

字典()

要创建字典,我们可以根据手册使用映射类型的内置dict函数,支持以下方法.

dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])
Run Code Online (Sandbox Code Playgroud)

最后一个选项表明我们提供了包含2个值或(key, value)元组的列表列表,因此我们希望将顺序列表转换为:

l = [["a", "b"], ["c", "d"], ["e",]]
Run Code Online (Sandbox Code Playgroud)

我们还介绍了该zip功能,该手册解释了其中一个内置功能:

返回元组列表,其中第i个元组包含每个参数的第i个元素

换句话说,如果我们可以将列表转换为两个列表a, c, e,b, d那么zip将完成剩下的工作.

切片表示法

我们看到的切片Strings一起使用,并且在List部分中进一步使用了切片主要使用范围短切片符号,但这就是长切片符号的样子以及我们可以用步骤完成的事情:

>>> l[::2]
['a', 'c', 'e']

>>> l[1::2]
['b', 'd']

>>> zip(['a', 'c', 'e'], ['b', 'd'])
[('a', 'b'), ('c', 'd')]

>>> dict(zip(l[::2], l[1::2]))
{'a': 'b', 'c': 'd'}
Run Code Online (Sandbox Code Playgroud)

虽然这是理解所涉及的机制的最简单方法,但是存在一个缺点,因为切片每次都是新的列表对象,这可以从这个克隆示例中看出:

>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]

>>> b is a
True

>>> b = a[:]
>>> b
[1, 2, 3]

>>> b is a
False
Run Code Online (Sandbox Code Playgroud)

尽管b现在看起来像是两个独立的物体,但这就是为什么我们更喜欢使用石斑鱼配方.

石斑鱼食谱

虽然石斑鱼被解释为itertools模块的一部分,但它与基本功能的完美结合.

一些严肃的伏都教吧?=)但实际上只不过是spice的一些语法糖,石斑鱼配方是通过以下表达式完成的.

*[iter(l)]*2
Run Code Online (Sandbox Code Playgroud)

或多或少转换为包含在列表中的同一迭代器的两个参数,如果这有意义的话.让我们分解它以帮助摆脱一些光.

拉链最短

>>> l*2
['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']

>>> [l]*2
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]

>>> [iter(l)]*2
[<listiterator object at 0x100486450>, <listiterator object at 0x100486450>]

>>> zip([iter(l)]*2)
[(<listiterator object at 0x1004865d0>,),(<listiterator object at 0x1004865d0>,)]

>>> zip(*[iter(l)]*2)
[('a', 'b'), ('c', 'd')]

>>> dict(zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd'}
Run Code Online (Sandbox Code Playgroud)

正如你所看到的那样,两个迭代器的地址保持不变所以我们正在使用相同的迭代器,然后首先获取一个键,然后是一个值,一个键和一个值,每次步进相同的迭代器来完成我们所做的切片更有成效.

你会完成同样的事情,下面带有一个更小的东西是什么?因素也许.

>>> it = iter(l)     
>>> dict(zip(it, it))
{'a': 'b', 'c': 'd'}
Run Code Online (Sandbox Code Playgroud)

e如果您注意到所有示例中都缺少了空键,那么因为zip选择了两个参数中最短的一个,所以我们该怎么做.

一个解决方案可能是在奇数长度列表中添加一个空值,你可以选择使用append和一个if可以做到这一点的语句,虽然有点无聊,对吧?

>>> if len(l) % 2:
...     l.append("")

>>> l
['a', 'b', 'c', 'd', 'e', '']

>>> dict(zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': ''}
Run Code Online (Sandbox Code Playgroud)

现在,在你耸耸肩走向类型之前,from itertools import izip_longest你可能会惊讶地知道它不是必需的,我们可以完成同样的,甚至更好的恕我直言,仅内置功能.

地图最长

我更喜欢使用map()函数而不是izip_longest(),它不仅使用较短的语法而且不需要导入,但它可以None在需要时自动分配实际的空值.

>>> l = ["a", "b", "c", "d", "e"]
>>> l
['a', 'b', 'c', 'd', 'e']

>>> dict(map(None, *[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': None} 
Run Code Online (Sandbox Code Playgroud)

正如KursedMetal所指出的那样,比较两种方法的性能,很明显,itertools模块远远超过了大量地图上的地图功能,作为1000万条记录显示的基准.

$ time python -c 'dict(map(None, *[iter(range(10000000))]*2))'
real    0m3.755s
user    0m2.815s
sys     0m0.869s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(10000000))]*2, fillvalue=None))'
real    0m2.102s
user    0m1.451s
sys     0m0.539s
Run Code Online (Sandbox Code Playgroud)

然而,导入模块的成本会对较小的数据集造成影响,当地图开始到达时,地图返回的速度要快得多,大约可达10万条记录.

$ time python -c 'dict(map(None, *[iter(range(100))]*2))'
real    0m0.046s
user    0m0.029s
sys     0m0.015s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100))]*2, fillvalue=None))'
real    0m0.067s
user    0m0.042s
sys     0m0.021s

$ time python -c 'dict(map(None, *[iter(range(100000))]*2))'
real    0m0.074s
user    0m0.050s
sys     0m0.022s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100000))]*2, fillvalue=None))'
real    0m0.075s
user    0m0.047s
sys     0m0.024s
Run Code Online (Sandbox Code Playgroud)

什么都看不见!=)

的nJoy!

  • Python 3 不支持 `map(None, ...)`,因此您的解决方案仅限于 Python 2.X (3认同)
  • Python 3.4.3 支持 map(None, ...),例如 dict(map(None, *[iter(l)]*2)) 返回 dict(map(None, *[iter(l)]*2))对于 l = ['a', 'b', 'c', 'd', 'e'] (2认同)

Sve*_*ach 46

使用通常的石斑鱼配方,您可以:

Python 2:

d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Run Code Online (Sandbox Code Playgroud)

Python 3:

d = dict(itertools.zip_longest(*[iter(l)] * 2, fillvalue=""))
Run Code Online (Sandbox Code Playgroud)

  • 你也可以这样做`d = dict(itertools.izip_longest(l [:: 2],l [1 :: 2],fillvalue =''))`,或者在Python 3中``d = dict(itertools.zip_longest) (l [:: 2],l [1 :: 2],fillvalue =''))`.你的版本运行得很好,但对于那些没有意识到`[iter(l)]*2`创建一个包含对同一个iterator_的两个引用的列表的人来说可能会有些混乱.(`[iter(l)]*2` - >`[<list_iterator对象位于0x01383FD0>,<list_iterator对象位于0x01383FD0>]`) (4认同)

Gio*_*tro 18

我会去递归:

l = ['a', 'b', 'c', 'd', 'e', ' ']
d = dict([(k, v) for k,v in zip (l[::2], l[1::2])])
Run Code Online (Sandbox Code Playgroud)

  • 我认为这已经足够了 `dict(zip(l[::2], l[1::2]))`。Python 3.8.5 对我来说效果很好 (3认同)
  • 为什么这是递归的?它对我来说很复杂. (2认同)