Python辞書:キーのリストの値のリストを取得する


182

対応する項目のリストを取得するために辞書へのキーのリストを使用する組み込み/迅速な方法はありますか?

たとえば、私は:

>>> mydict = {'one': 1, 'two': 2, 'three': 3}
>>> mykeys = ['three', 'one']

mykeys辞書の対応する値をリストとして取得するにはどうすればよいですか?

>>> mydict.WHAT_GOES_HERE(mykeys)
[3, 1]

回答:


206

リスト内包はこれを行うための良い方法のようです:

>>> [mydict[x] for x in mykeys]
[3, 1]

1
mydict(dictを返す)関数呼び出しの場合、これは関数を複数回呼び出しますよね?
内部石2018

1
@endolithはい、そうです
Eric Romrell

108

list-comp以外のいくつかの方法:

  • リストを作成し、キーが見つからない場合は例外をスローします。 map(mydict.__getitem__, mykeys)
  • Noneキーが見つからない場合のリストの作成:map(mydict.get, mykeys)

または、次を使用しoperator.itemgetterてタプルを返すことができます。

from operator import itemgetter
myvalues = itemgetter(*mykeys)(mydict)
# use `list(...)` if list is required

:Python3ではmap、リストではなくイテレータを返します。list(map(...))リストに使用します。


54

少し速度の比較:

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

そのため、リスト内包表記とアイテムゲッターは、これを行う最も速い方法です。

更新:大きなランダムリストとマップの場合、結果が少し異なりました。

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)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit map(m.__getitem__, l)
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit map(m.get, l)
%timeit map(lambda _: m[_], l)
1000 loops, best of 3: 1.14 ms per loop
1000 loops, best of 3: 1.68 ms per loop
100 loops, best of 3: 2 ms per loop
100 loops, best of 3: 2.05 ms per loop
100 loops, best of 3: 2.19 ms per loop
100 loops, best of 3: 2.53 ms per loop
100 loops, best of 3: 2.9 ms per loop

したがって、この場合の明確な勝者はf = operator.itemgetter(*l); f(m)であり、明確な外部者です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)
%timeit list(itemgetter(*l)(m))
%timeit [m[_] for _ in l]  # list comprehension
%timeit list(map(m.__getitem__, l))
%timeit list(m[_] for _ in l)  # a generator expression passed to a list constructor.
%timeit list(map(m.get, l))
%timeit list(map(lambda _: m[_], l)
1.66 ms ± 74.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
2.1 ms ± 93.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.58 ms ± 88.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.36 ms ± 60.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.98 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.7 ms ± 284 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
3.14 ms ± 62.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

したがって、Python 3.6.4の結果はほぼ同じです。


15

3つの方法があります。

上げる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]

found_keys = mapping.keys() & iterableTypeError: unsupported operand type(s) for &: 'list' and 'list'Python 2.7 を与える; `found_keys = [反復可能なキーの場合、mapping.keys()のキーのキー]が最も効果的
NotGaeL


7

これを試して:

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]

@PeterDeGlopper混乱しています。items()追加のルックアップを行う必要はなく、len(mydict)*len(mykeys)ここでは操作はありません!(私はセットを使っているという通知)
オスカル・ロペス

@ÓscarLópezはい、あります。辞書のすべての要素を検査しています。iteritemsは必要になるまでそれらを生成しないため、中間リストの作成を回避しますが、mydictのすべてのkに対して「k in mykeys」(リストであるため、len(mykeys)の順序)を実行します。mykeysだけを実行する単純なリスト内包と比較すると、完全に不必要です。
Peter DeGlopper 2013

@ inspectorG4dget @PeterDeGlopperメンバーシップの操作にわたりmykeys一定の償却時間、私はセットを使用している、いないリストがある
オスカル・ロペス

2
OPのリストをセットに変換すると、少なくとも線形になりますが、順序が失われるだけでなく、誤ったデータ構造でも線形になります。10k辞書とmykeysの2つのキーの場合を考えてみます。ソリューションでは、単純なリストの理解のための2つの辞書ルックアップと比較して、1万セットのメンバーシップテストを行います。一般に、キーの数はディクショナリ要素の数よりも少ないと想定するのが安全であると思われます。そうでない場合、アプローチは繰り返される要素を省略します。
Peter DeGlopper


1

Pandasはこれを非常にエレガントに行いますが、多くの場合、リスト内包表記は常に技術的にはPythonicです。現在、速度比較を行う時間はありません(後で戻ってそれを入れます):

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}

-1

または、mydict.keys()それは辞書の組み込みメソッド呼び出しです。また、探検mydict.values()mydict.items()

//ああ、OPポストは私を混乱させた。


5
組み込みのメソッドは便利ですが、指定されたキーのリストから対応するアイテムのリストを提供しません。この答えは、この特定の質問に対する正しい答えではありません。
stenix 2015

-1

Pythonの終了後 :dict値から指定された順序でリストを作成する効率的な方法

リストを作成せずにキーを取得する:

from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import collections


class DictListProxy(collections.Sequence):
    def __init__(self, klist, kdict, *args, **kwargs):
        super(DictListProxy, self).__init__(*args, **kwargs)
        self.klist = klist
        self.kdict = kdict

    def __len__(self):
        return len(self.klist)

    def __getitem__(self, key):
        return self.kdict[self.klist[key]]


myDict = {'age': 'value1', 'size': 'value2', 'weigth': 'value3'}
order_list = ['age', 'weigth', 'size']

dlp = DictListProxy(order_list, myDict)

print(','.join(dlp))
print()
print(dlp[1])

出力:

value1,value3,value2

value3

リストで指定された順序と一致します


-2
reduce(lambda x,y: mydict.get(y) and x.append(mydict[y]) or x, mykeys,[])

辞書にないキーがある場合。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.