キーに特定の文字列が含まれているpython辞書のアイテムをフィルタリングする


95

私はPythonで何かを開発しているCコーダーです。Cで(したがって、Pythonに適用されたCのようなロジックで)以下を実行する方法を知っていますが、それを実行する「Python」の方法は何なのかと思っています。

私には辞書dがあり、アイテムのサブセットを操作したいのですが、キー(文字列)の人だけが特定の部分文字列を含んでいます。

つまり、Cロジックは次のようになります。

for key in d:
    if filter_string in key:
        # do something
    else
        # do nothing, continue

私はPythonバージョンが次のようなものになると想像しています

filtered_dict = crazy_python_syntax(d, substring)
for key,value in filtered_dict.iteritems():
    # do something

辞書のフィルタリングに関する投稿はたくさんありますが、これに関係する投稿は見つかりませんでした。

辞書がネストされておらず、Python 2.7を使用しています



回答:


182

どの程度のdictの理解

filtered_dict = {k:v for k,v in d.iteritems() if filter_string in k}

あなたがそれを見れば、それは英語のようにかなりよく読むので、それは自明であるはずです。

この構文にはPython 2.7以降が必要です。

Python 3にはのみdict.items()がありiteritems()、次のように使用します。

filtered_dict = {k:v for (k,v) in d.items() if filter_string in k}

1
なんでfiltered_dict = {k:d[k] for k in d if filter_string in k}
thefourtheye 2014年

5
@thefourtheye私はそれがルックアップにインカレントではないので、私の方が速いと推測d[k]ます。
Jonathon Reinhart、2014年

また、彼は# do somethingコメントで言っていますが、ここではいくつかのキーをドロップします。
thefourtheye 2014年

我々は持っていますiteritemsPythonの3に?私はそうは思いません。だから、私のバージョンは互換性がありますか?
thefourtheye 2014年

1
Pythonの3では、あなたが代わるiteritemsitemsはPython 2.7のと同じです、iteritems
Jonathon Reinhart、2014年

17

最も読みやすく、簡単に保守できるものを選びましょう。あなたがそれを一行で書き出すことができるからといって、あなたがそうすべきだという意味ではありません。あなたの既存のソリューションは、iteritemsを使用して値のルックアップをスキップする以外は、私が使用するものに近く、それらを回避できる場合はネストされたifsを使用しません。

for key, val in d.iteritems():
    if filter_string not in key:
        continue
    # do something

ただし、本当にフィルター処理されたディクトレットを反復処理できるようにしたい場合は、フィルター処理されたディクショナリーを構築してそれを反復処理する2つのステップのプロセスを実行せず、代わりにジェネレーターを使用します。発電機?

最初にジェネレーターを作成します。優れた設計では、ジェネレーターを抽象化して再利用できるようにする必要があります。

# The implementation of my generator may look vaguely familiar, no?
def filter_dict(d, filter_string):
    for key, val in d.iteritems():
        if filter_string not in key:
            continue
        yield key, val

そして、ジェネレーターを使用して、シンプルで理解しやすいコードで問題をきれいに解決できます。

for key, val in filter_dict(d, some_string):
    # do something

つまり、ジェネレーターは素晴らしいです。


11

組み込みのフィルタ機能を使用して、特定の条件に基づいて辞書、リストなどをフィルタリングできます。

filtered_dict = dict(filter(lambda item: filter_str in item[0], d.items()))

利点は、さまざまなデータ構造に使用できることです。


ラムダ定義に含まれているitems:必要があることitem:に注意してください。
bkribbs 2018

エラーを指摘してくれて@bkribbsに感謝します。私はそれを修正しました。
プルキット2018

8
input = {"A":"a", "B":"b", "C":"c"}
output = {k:v for (k,v) in input.items() if key_satifies_condition(k)}

3
私の方法を使用iteritems()すると、よりも効率的になりitems()ます。
Jonathon Reinhart、2014年

@Jonathin Reinhart私はそれについて知りませんでした。ありがとう。
jspurim 2014年

2
Python 2.7のみ。Python 3には、Python 2.7のように動作するだけ items()がありiteritemsます。
Jonathon Reinhart、2014年

1
質問は明示的にpython 2.7向けです
ブレンダンF

7

ジョナソンは彼の答えに口述の理解を使用するアプローチをあなたに与えまし。ここにあなたの何かを扱うアプローチがあります部分。

辞書の値を使用して何かを実行したい場合、辞書の理解はまったく必要ありません。

私は使っています iteritems()ています

results = map(some_function, [(k,v) for k,v in a_dict.iteritems() if 'foo' in k])

これで、結果はリストになり、some_functionキーにあるディクショナリの各キー/値ペアに適用されfooます。

値を処理し、キーを無視するだけの場合は、リストの内包を変更するだけです。

results = map(some_function, [v for k,v in a_dict.iteritems() if 'foo' in k])

some_function 呼び出し可能であれば、ラムダも機能します。

results = map(lambda x: x*2, [v for k,v in a_dict.iteritems() if 'foo' in k])

ジェネレータ式を渡してマップすることもできるため、実際には内部リストは必要ありません。

>>> map(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))
[4]

面白い。some_functionはどのように定義されますか?最初のケース(k、v)では、2つのパラメーターのみを受け取りますか?最初のキー、次に値?
2014年

はい、呼び出し可能です。だからmap(lambda a: a[0]*a[1], ((k,v) for k,v in {2:2, 3:2}.iteritems() if k == 2))-これはあなたに与えるでしょう[4]
はBurhanハリド

これは正しいですが、使用するよりもpythonicの方mapがリスト内包です。[f(v) for k, v in d.iteritems() if substring in k]私はそれがはるかに読みやすく、より効率的だと思います。
Davidmh 2014年

@メモ2つのパラメーターをとるのではなく、2つの要素を持つ単一のパラメーターをとります。2つの引数にアンパックするstarmapもありますが、これは遅延イテレーターです(つまりresults = list(starmap(...))、実行する前に反復する必要がありますfor result in starmap(...): ...。つまり、または)。
nmclean 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.