l = ["a", "b", "c", "d", "e"]
我想将此列表转换为字典,如:
d = {"a": "b", "c": "d", "e": ""}
所以基本上,evens 将是键,而赔率将是值。我知道我可以以“非 pythonic”的方式做到这一点,例如带有 if 语句的 for 循环,但我相信应该有一个更“pythonic”的方式来实现这一点。
如果你还在想什么!你不会孤单,它实际上并不复杂,真的,让我解释一下。
如何仅使用内置函数将列表转换为字典
我们想把的列表变成一个字典,使用奇数条目(从 1 开始计数)作为映射到其连续偶数条目的键。
l = ["a", "b", "c", "d", "e"]
dict ()
要创建一个字典,我们可以使用内置的dict
函数Mapping Types根据手册支持以下方法。
dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])
最后一个选项建议我们提供一个包含 2 个值或(key, value)
元组的列表列表,因此我们希望将顺序列表转换为:
l = [["a", "b"], ["c", "d"], ["e",]]
我们还介绍了zip
函数,one of the built-in functions手册解释:
返回元组列表,其中第 i 个元组包含每个参数中的第 i 个元素
换句话说,如果我们可以将我们的列表变成两个列表a, c, e
和b, d
,那么zip
将完成其余的工作。
切片表示法
Slicings,我们看到它与Strings一起使用,并且在List section中也进一步使用,它主要使用范围或短切片表示法,但这就是长切片表示法的样子,我们可以用步骤完成:
>>> 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'}
尽管这是理解所涉及的机制的最简单的方法,但有一个缺点,因为切片每次都是新的列表对象,正如这个克隆示例所示:
>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]
>>> b is a
True
>>> b = a[:]
>>> b
[1, 2, 3]
>>> b is a
False
即使 b 看起来像 a,它们现在是两个独立的对象,这就是为什么我们更喜欢使用grouper recipe。
石斑鱼食谱
虽然石斑鱼被解释为 itertools 模块的一部分,但它也可以与基本功能完美配合。
一些严重的伏都教对吗?=)但实际上只不过是香料的一点语法糖,石斑鱼食谱由以下表达式完成。
*[iter(l)]*2
这或多或少转化为包装在列表中的同一个迭代器的两个参数,如果这有任何意义的话。
zip 最短
>>> 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'}
正如你所看到的,两个迭代器的地址保持不变,所以我们使用相同的迭代器,zip 然后首先从获取一个键,然后获取一个值和一个键和值,每次步进相同的迭代器来完成我们所做的切片更有效。
您将完成与以下相同的内容,其中包含一个较小的什么?因素也许。
>>> it = iter(l)
>>> dict(zip(it, it))
{'a': 'b', 'c': 'd'}
空键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': ''}
现在,在你耸耸肩去输入from itertools import izip_longest
之前,你可能会惊讶地知道它不是必需的,我们可以完成相同的,甚至更好的 IMHO,仅使用内置功能。
最长的地图
我更喜欢使用map() function而不是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}
正如 KursedMetal 所指出的,比较这两种方法的性能,很明显,itertools 模块在大卷上的性能远远优于 map 函数,作为 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
然而,导入模块的成本对较小的数据集造成了损失,当它们开始头对头到达时,地图返回的速度要快得多,达到大约 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
看不到任何东西!=)
nJoy!
使用通常的grouper recipe,你可以做:
Python 2:d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Python 3:
d = dict(itertools.zip_longest(*[iter(l)] * 2, fillvalue=""))
我会去递归:
l = ['a', 'b', 'c', 'd', 'e', ' ']
d = dict([(k, v) for k,v in zip (l[::2], l[1::2])])
不知道它是否会帮助你,但它对我有用:
l = ["a", "b", "c", "d", "e"]
outRes = dict((l[i], l[i+1]) if i+1 < len(l) else (l[i], '') for i in xrange(len(l)))
本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处
评论列表(32条)