是否有一种内置/快速的方法来使用字典的键列表来获得对应项的列表?
例如,我有:
>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']
我如何使用mykeys在字典中作为列表获得相应的值?
>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]
是否有一种内置/快速的方法来使用字典的键列表来获得对应项的列表?
例如,我有:
>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']
我如何使用mykeys在字典中作为列表获得相应的值?
>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]
当前回答
比较一下速度:
Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec 7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[1]: l = [0,1,2,3,2,3,1,2,0]
In[2]: m = {0:10, 1:11, 2:12, 3:13}
In[3]: %timeit [m[_] for _ in l] # list comprehension
1000000 loops, best of 3: 762 ns per loop
In[4]: %timeit map(lambda _: m[_], l) # using 'map'
1000000 loops, best of 3: 1.66 µs per loop
In[5]: %timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.
1000000 loops, best of 3: 1.65 µs per loop
In[6]: %timeit map(m.__getitem__, l)
The slowest run took 4.01 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 853 ns per loop
In[7]: %timeit map(m.get, l)
1000000 loops, best of 3: 908 ns per loop
In[33]: from operator import itemgetter
In[34]: %timeit list(itemgetter(*l)(m))
The slowest run took 9.26 times longer than the fastest. This could mean that an intermediate result is being cached
1000000 loops, best of 3: 739 ns per loop
列表理解和itemgetter是最快的方法。
更新
对于大型随机列表和地图,我得到了一些不同的结果:
Python 2.7.11 |Anaconda 2.4.1 (64-bit)| (default, Dec 7 2015, 14:10:42) [MSC v.1500 64 bit (AMD64)] on win32
In[2]: import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
1000 loops, best of 3: 1.14 ms per loop
%timeit list(itemgetter(*l)(m))
1000 loops, best of 3: 1.68 ms per loop
%timeit [m[_] for _ in l] # list comprehension
100 loops, best of 3: 2 ms per loop
%timeit map(m.__getitem__, l)
100 loops, best of 3: 2.05 ms per loop
%timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.
100 loops, best of 3: 2.19 ms per loop
%timeit map(m.get, l)
100 loops, best of 3: 2.53 ms per loop
%timeit map(lambda _: m[_], l)
100 loops, best of 3: 2.9 ms per loop
所以在这种情况下,明显的赢家是f = operator。itemgetter(*l);F (m)和clear outsider: map(lambda _: m[_], l)。
Python 3.6.4更新
import numpy.random as nprnd
l = nprnd.randint(1000, size=10000)
m = dict([(_, nprnd.rand()) for _ in range(1000)])
from operator import itemgetter
import operator
f = operator.itemgetter(*l)
%timeit f(m)
1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit list(itemgetter(*l)(m))
2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit [m[_] for _ in l] # list comprehension
2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(map(m.__getitem__, l))
2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(m[_] for _ in l) # a generator expression passed to a list constructor.
2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(map(m.get, l))
2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit list(map(lambda _: m[_], l)
3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
因此,Python 3.6.4的结果几乎相同。
其他回答
试试这个:
mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one'] # if there are many keys, use a set
[mydict[k] for k in mykeys]
=> [3, 1]
reduce(lambda x,y: mydict.get(y) and x.append(mydict[y]) or x, mykeys,[])
以防字典里没有钥匙。
这里有三种方法。
当找不到key时引发KeyError:
result = [mapping[k] for k in iterable]
缺少键的默认值。
result = [mapping.get(k, default_value) for k in iterable]
跳过丢失的键。
result = [mapping[k] for k in iterable if k in mapping]
Pandas非常优雅地做到了这一点,尽管ofc列表理解在技术上总是更加python化。我现在没有时间放一个速度比较(我稍后会回来放):
import pandas as pd
mydict = {'one': 1, 'two': 2, 'three': 3}
mykeys = ['three', 'one']
temp_df = pd.DataFrame().append(mydict)
# You can export DataFrames to a number of formats, using a list here.
temp_df[mykeys].values[0]
# Returns: array([ 3., 1.])
# If you want a dict then use this instead:
# temp_df[mykeys].to_dict(orient='records')[0]
# Returns: {'one': 1.0, 'three': 3.0}
除了list-comp,还有其他几种方法:
如果key未找到,则生成列表并抛出异常:__getitem__ mykey) 如果没有找到键,则使用None构建列表:得到,mykey)
或者,使用operator。Itemgetter可以返回一个元组:
from operator import itemgetter
myvalues = itemgetter(*mykeys)(mydict)
# use `list(...)` if list is required
注意:在Python3中,map返回一个迭代器而不是一个列表。使用list(map(…))作为列表。