Python辞書の値のマッピング


243

関数を渡して提供し{ k1: v1, k2: v2 ... }たい辞書{ k1: f(v1), k2: f(v2) ... }があるとしますf

そのような組み込み関数はありますか?または私はしなければなりませんか

dict([(k, f(v)) for (k, v) in my_dictionary.iteritems()])

理想的には、

my_dictionary.map_values(f)

または

my_dictionary.mutate_values_with(f)

つまり、元の辞書が変異しているか、コピーが作成されているかは、私には関係ありません。


2
あなたの例を書くより良い方法はdict((k, f(v)) for k, v in mydict.iteritems())、すなわち、角括弧なしで、ジェネレータを介した中間リストの作成を防ぐでしょう。
bereal

回答:


354

そのような機能はありません。これを行う最も簡単な方法は、dict内包表記を使用することです。

my_dictionary = {k: f(v) for k, v in my_dictionary.items()}

Python 2.7では、.iteritems()代わりにメソッドを使用して.items()メモリを節約します。dict内包構文はpython 2.7まで導入されませんでした。

リストにもそのようなメソッドがないことに注意してください。リスト内包表記またはmap()関数を使用する必要があります。

そのため、map()関数を使用して辞書を処理することもできます。

my_dictionary = dict(map(lambda kv: (kv[0], f(kv[1])), my_dictionary.iteritems()))

しかし、それは実際にはそれほど読みやすいものではありません。


5
+1:これも私がすることです。 dict(zip(a, map(f, a.values())))少し短いですが、何をしているのかを考えなければなりません。そして、そうです。dictが変更されない場合、キーと値は同じ順序で繰り返されます。私はdictcompが何をしているかについてまったく考える必要がないので、それが正しい答えです。
DSM

2
@chiborg:これは、すべてのキーと値のペアを一度に検索するのではなく、number-of-keys回のmy_dictionary.__getitem__呼び出しを使用しているためです。
Martijn Pieters

1
PEP3113(python 3.xで実装)以降、タプルパラメータはサポートされなくなったことに注意してください。これlambda (k,v): (k, f(v))は次のように書き直されますlambda k_v: (k_v[0], f(k_v[1]))
18:53の

1
なぜパラメーターのアンパックがnixedになったのですか?どのように改善されていますか?
javadba 2018

3
FP言語から来たPythonは信じられないほど扱いにくいように思えます。
ジャンキト


21

これは、新しい辞書を作成するのではなく、インプレースで実行できます。これは、大規模な辞書(コピーが必要ない場合)に適している場合があります。

def mutate_dict(f,d):
    for k, v in d.iteritems():
        d[k] = f(v)

my_dictionary = {'a':1, 'b':2}
mutate_dict(lambda x: x+1, my_dictionary)

my_dictionary含む結果:

{'a': 2, 'b': 3}

1
かっこいい、名前mapdictを変更しmutate_values_withたり、辞書を書き直したりできるようにする必要があります。:)
Tarrasch 2014

2
zip(d.keys(), d.values())代わりに、より多くのバージョンで動作しますiteritems()
ytpillai 2015

1
@ytpillai 'zip'または内包は、値をインプレースで変更するのではなく、コピーを作成します。これが私の回答の目的です。受け入れられた回答は、コピーに問題がない場合に最適です。
2015

1
申し訳ありませんが、itemsメソッドを使用したいとは思いませんでした。ただし、これをさらに改善することもできます(Python 2.7を使用していない場合){k:f(v) for k,v in iter(d.items())}
ytpillai

1
イテレータを作成してスペースを
節約


4

私の元の答えは要点を逃しましたが(defaultdictのファクトリーでAccessing keyのソリューションを使用してこの問題を解決しようとしたため)、現在の質問に対する実際のソリューションを提案するためにそれを作り直しました。

ここにあります:

class walkableDict(dict):
  def walk(self, callback):
    try:
      for key in self:
        self[key] = callback(self[key])
    except TypeError:
      return False
    return True

使用法:

>>> d = walkableDict({ k1: v1, k2: v2 ... })
>>> d.walk(f)

アイデアは、元の辞書をサブクラス化して必要な機能を提供することです。つまり、すべての値に関数を「マッピング」します。

プラス点は、このディクショナリを使用しdictて、コールバックで要求に応じてデータを変換しながら、元のデータをであるかのように格納できることです。

もちろん、クラスと関数に自由に名前を付けてください(この回答で選択した名前は、PHPのarray_walk()関数に影響を受けています)。

注:どちらもtry- exceptブロックやreturn文は機能性のために必須です、彼らはそこにさらに模倣するためにPHPの振る舞いのですarray_walk


1
__missing__渡されたファクトリメソッドが何らかの方法でフォールバックとしてorigin dictを使用しない限り、メソッドは既存のキーに対して呼び出されないため、これはOPの質問を解決できませんが、使用例の一部ではないため、私はこれを当面の問題に対して不十分な答えだと考えています。
Kaos、2016

既存のキーはどれですか?
7heo.tk

OPから:Given a dictionary { k1: v1, k2: v2 ... } ...。つまり、あなたはすでにdict最初から..
Kaos

私たちはどちらも正しいと言いたいです。しかし、私たちはどちらも間違っていると思います。私の答えが質問に答えないというのはあなたの言う通りです。ただし、呼び出した理由ではありません。私は単純に要点を逃し、{v1: f(v1), v2: f(v2), ...}与えられたを取得する方法を[v1, v2, ...]与え、口述は与えられませんでした。回答を編集して修正します。
7heo.tk

2

次のようにラムダ内からインデックスを作成しないようにするには:

rval = dict(map(lambda kv : (kv[0], ' '.join(kv[1])), rval.iteritems()))

あなたも行うことができます:

rval = dict(map(lambda(k,v) : (k, ' '.join(v)), rval.iteritems()))

これは、2番目の例の2タプル自体の中の巧妙な操作です。ただし、Python 3ではサポートされなくなったラムダ内での自動タプルアンパックを利用しています。したがって、機能しlambda(k,v)ません。stackoverflow.com/questions/21892989/…を
Jonathan Komar

0

ちょうどこのユースケースに遭遇しました。私はgensの回答を実装し、dictでもある値を処理するための再帰的なアプローチを追加しました。

def mutate_dict_in_place(f, d):
    for k, v in d.iteritems():
        if isinstance(v, dict):
            mutate_dict_in_place(f, v)
        else:
            d[k] = f(v)

# Exemple handy usage
def utf8_everywhere(d):
    mutate_dict_in_place((
        lambda value:
            value.decode('utf-8')
            if isinstance(value, bytes)
            else value
        ),
        d
    )

my_dict = {'a': b'byte1', 'b': {'c': b'byte2', 'd': b'byte3'}}
utf8_everywhere(my_dict)
print(my_dict)

これは、Python 2で文字列をバイトとしてエンコードするjsonまたはyamlファイルを処理するときに役立ちます。

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