web-dev-qa-db-ja.com

Python辞書の値をマッピングする

辞書{ k1: v1, k2: v2 ... }が与えられたとき、私はfという関数を渡したならば{ k1: f(v1), k2: f(v2) ... }を手に入れたいです。

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

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

理想的には私はちょうど書くだろう

my_dictionary.map_values(f)

または

my_dictionary.mutate_values_with(f)

つまり、元の辞書が変更されていてもコピーが作成されていても構いません。

197
Tarrasch

そのような機能はありません。これを行う最も簡単な方法は、辞書の理解を使用することです。

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

Python 2.7では、メモリを節約するために.iteritems()の代わりに.items()メソッドを使います。辞書理解構文はpython 2.7まで導入されませんでした。

リストにもそのようなメソッドはありません。リスト内包表記かmap()関数を使う必要があります。

そのため、辞書の処理にもmap()関数を使用できます。

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

しかし、それはそれほど可読ではありません、本当に。

280
Martijn Pieters

これらのツールは、この種の単純でありながら反復的なロジックに最適です。

http://toolz.readthedocs.org/en/latest/api.html#toolz.dicttoolz.valmap

あなたがなりたい場所にあなたを正しくします。

import toolz
def f(x):
  return x+1

toolz.valmap(f, my_list)
22
Jesse Smith

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

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}
19
gens

私の最初の答えは( defaultdictのファクトリ内のキーにアクセスする )の解決策でこの問題を解決しようとすることによってポイントを逃しましたが、私は現在の質問に対する実際の解決策を提案するためにそれを作り直しました。

ここにあります:

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() functionに触発されています)。

注:try-exceptブロックもreturnステートメントも機能上必須ではありません。これらは、PHPのarray_walkの動作をさらに模倣するためにあります。

4
7heo.tk

Python 3.xでは PEP-0469 がiteritems()をitems()に変更し、 PEP-311 が削除されたためTuple parameter unpackingあなたは Martijn Pieters♦answer のように書くべきです:

my_dictionary = dict(map(lambda item: (item[0], f(item[1])), my_dictionary.items()))
4
lucidyan

このユースケースに出会ったばかりです。私は gens's answer を実装しました。これもまた、値である値を処理するための再帰的なアプローチを追加したものです。

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ファイルを扱うときに便利です。

0
Oyono

次のように、ラムダの内側からインデックスを作成しないようにします。

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

次のこともできます。

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