辞書の値とキーを交換するにはどうすればよいですか?


96

辞書を入力として受け取り、そのキーが入力の値となり、その値が対応する入力キーとなる辞書を返したいのですが。値は一意です。

たとえば、私の入力は次のとおりです。

a = dict()
a['one']=1
a['two']=2

私の出力を次のようにしたいと思います:

{1: 'one', 2: 'two'}

明確にするために、私の結果を以下と同等にしたいと思います:

res = dict()
res[1] = 'one'
res[2] = 'two'

これを達成するためのきちんとしたPython的な方法はありますか?


1
Python 3を使用している場合に適切な回答が得られる同一の質問については、stackoverflow.com / questions / 1087694 / …を参照してください
スティーブンエドモンズ

@Stephen:2番目に投票された回答を参照してください。これは、リンクした質問で承認された回答と同じです。群衆は他の答えを好んだが...
Roee Adler

4
PythonはPerlではなく、PythonはRubyではありません。読みやすさが重要です。疎は密よりも優れています。これを考えると、これらの回答のすべての方法は単に悪い™です。問題の1つは行くための最良の方法です。
o0 '。

回答:


147

Python 2:

res = dict((v,k) for k,v in a.iteritems())

Python 3(@erikに感謝):

res = dict((v,k) for k,v in a.items())

14
これは正しいようですが、コードだけでなく、それがどのように機能するかの説明を追加することは本当に良いことです。
ウィル

4
値が一意でない場合はどうなりますか?次に、キーはリストでなければなりません...例:d = {'a':3、 'b':2、 'c':2} {d.iteritems()のk、vのv:k} { 2: 'b'、3: 'a'}は{2:['b'、 'c']、3: 'a'}
Hanan Shteingart

4
@HananShteingart:OPの質問で述べられた値はユニークです。あなたのケースのために別の質問投稿を作成してください(そしてできれば他の人のためにリンクしてください)
liori 2017

python2コードは動作します...しかし、リストの内包が不足している[]。リスト内包表記は[andを必要とし]ませんか?
Trevor Boyd Smith、

@TrevorBoydSmith:これはリスト内包表記ではなく、ジェネレータ式です。
liori

55
new_dict = dict(zip(my_dict.values(), my_dict.keys()))

4
本当にvalues()とkeys()が同じ順序を持つことが保証されていますか?
Lennart Regebro 2009

1
はい、python.org / dev / peps / pep-3106から仕様は、アイテムが.keys()、. values()および.items()によって返される順序が同じであることを意味します(Pythonの場合と同じです) 2.x)。これは、順序がすべてdictイテレータから派生しているためです(これはおそらく任意ですが、dictが変更されない限り安定しています)。しかし、この答えはmy_dictを2回呼び出す必要があります(1つは値、もう1つはキー)。多分これは理想的ではありません。
sunqiang 2009

4
はい、この回答は、dictを2回繰り返します。sunqiangの答えは、1回の反復しか必要としないため、大きな辞書には適しています。
カールマイヤー

@Carl Meyer:同意します。また、彼は大きなデータセットにははるかに優れたitertoolsを使用しています。最後のdict()呼び出しもストリーミングされているのか、それとも最初にペア全体のリストが作成されているのか
Javier

@CarlMeyerはさらにn> 1e6(または1e9)の場合、メモリ使用量も非常に大きくなります。これにより、速度が遅くなります。
Trevor Boyd Smith、

47

3.0以降を含むPython 2.7以降には、間違いなく短くて読みやすいバージョンがあります。

>>> my_dict = {'x':1, 'y':2, 'z':3}
>>> {v: k for k, v in my_dict.items()}
{1: 'x', 2: 'y', 3: 'z'}

30
In [1]: my_dict = {'x':1, 'y':2, 'z':3}

In [2]: dict((value, key) for key, value in my_dict.iteritems())
Out[2]: {1: 'x', 2: 'y', 3: 'z'}

3
元の質問ではありませんが、元の辞書に重複した値があり、このメソッドでキー/値を交換した場合、どうなるのでしょうか?
Andre Miller、

2
@Andre Miller:特定のキーの最後のオカレンスを受け取ります:dict(((1,3)、(1,2)))== {1:2}
balpha 09/06/07

2
重複は、最後に遭遇した重複で上書きされます。
クリストファー

2
@Andre Miller:そして、d.items()は任意の順序でアイテムを返すため、重複する値の任意のキーを取得します。
Ants Aasma 2009

私が見つけた最後のキーと値のペアが必要になると思います。それは、あなたが[「X」] = 4を設定し、[「X」] = 3のようなものだ
リザ・


18

あなたは試すことができます:

d={'one':1,'two':2}
d2=dict((value,key) for key,value in d.iteritems())
d2
  {'two': 2, 'one': 1}

次の場合、辞書を「逆転」できないことに注意してください。

  1. 複数のキーが同じ値を共有します。例えば{'one':1,'two':1}。新しいディクショナリは、キーを持つアイテムを1つだけ持つことができます1
  2. 1つ以上の値がハッシュ化できません。例えば{'one':[1]}[1]は有効な値ですが、有効なキーではありません。

この件に関する議論については、pythonメーリングリストのこのスレッドを参照してください。


また、元の辞書の値が一意であることを確認することに関するメモについても+1してください。そうしないと、「リバース」ディクテーションで上書きされます...そしてこれ(私はこれを私のコストで見つけました)は、コードにトリッキーなバグを引き起こす可能性があります!
モノジョニー

15

現在の主な答えは、値が一意であると想定していますが、常にそうであるとは限りません。値が一意でない場合はどうなりますか?あなたは情報を失うでしょう!例えば:

d = {'a':3, 'b': 2, 'c': 2} 
{v:k for k,v in d.iteritems()} 

戻り値 {2: 'b', 3: 'a'}

に関する情報'c'は完全に無視されました。理想的には、{2: ['b','c'], 3: ['a']}。これが一番下の実装です。

Python 2.x

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.iteritems():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv

Python 3.x

def reverse_non_unique_mapping(d):
    dinv = {}
    for k, v in d.items():
        if v in dinv:
            dinv[v].append(k)
        else:
            dinv[v] = [k]
    return dinv

それはより一般的なケースを覆っているため、これは正しい答えでなければなりません
レオン・ライ

これありがとう!他のソリューションでは情報が失われていました。
Cam

14

res = dict(zip(a.values(), a.keys()))


4
dictは、values()とkeys()が同じ順序で要素を返すことを保証しません。また、keys()、values()、およびzip()は、イテレータで十分なリストを返します。
liori 09年

19
@liori:あなたは間違っている。dictは、もちろんvalues()とkeys()の呼び出し間のdictを変更しない場合、values()とkeys()が同じ順序になることを保証します。ドキュメントには、次のように記載されています:(「メモ」の部分:docs.python.org/library/stdtypes.html#dict.itemsを読んでください)「If items()、keys()、values()、iteritems()、iterkeys( )、およびitervalues()が呼び出され、辞書に変更を加えることなく、リストが直接対応します。」
nosklo 2009年

1
OK、それから私は間違っています...私はオンラインドキュメントをチェックしていません。これを指摘していただきありがとうございます。
liori 09年

この回答をより効率的にするために、zipの代わりにイテレーターitertools.izipを使用できます。
Alasdair

そしてiterkeysとitervalues。しかし、iteritems()を使用することもできます
nosklo

14
new_dict = dict( (my_dict[k], k) for k in my_dict)

またはそれ以上に優れていますが、Python 3でのみ機能します。

new_dict = { my_dict[k]: k for k in my_dict}

2
実際、Dict Comprehensions(PEP 274)はPython 2.7でも動作します。
Arseny 2013

10

Ilya Prokinの応答を拡張する別の方法は、実際にreversed関数を使用することです。

dict(map(reversed, my_dict.items()))

本質的に、辞書は(を使用して.items())反復され、各項目はキーと値のペアであり、それらの項目はreversed関数と交換されます。これがdictコンストラクタに渡されると、それらは必要な値/キーのペアに変換されます。


6

ハビエル答えの改善のための提案:

dict(zip(d.values(),d))

イテレータでディクショナリを通過すると、関連するディクショナリのキーが返されるため、d.keys()単にの代わりにを書くことができdます。

例 この動作の場合:

d = {'a':1,'b':2}
for k in d:
 k
'a'
'b'


2
dict(map(lambda x: x[::-1], YourDict.items()))

.items()のタプルのリストを返します(key, value)map()リストの要素をlambda x:[::-1]調べ、その各要素(タプル)に適用してそれを逆にします。そのため、各タプル(value, key)はマップから吐き出された新しいリストになります。最後に、dict()新しいリストから辞書を作成します。


.items()はタプル(キー、値)のリストを返します。map()はリストの要素を通過lambda x:[::-1]し、その各要素(タプル)に適用してそれを逆にします。そのため、各タプルは、マップから吐き出された新しいリストの(値、キー)になります。最後に、dict()は新しいリストからdictを作成します。
Ilya Prokin、2015

1

ループの使用:-

newdict = {} #Will contain reversed key:value pairs.

for key, value in zip(my_dict.keys(), my_dict.values()):
    # Operations on key/value can also be performed.
    newdict[value] = key

1

Python3を使用している場合は、少し異なります。

res = dict((v,k) for k,v in a.items())

1

インプレースソリューションの追加:

>>> d = {1: 'one', 2: 'two', 3: 'three', 4: 'four'}
>>> for k in list(d.keys()):
...     d[d.pop(k)] = k
... 
>>> d
{'two': 2, 'one': 1, 'four': 4, 'three': 3}

Python3では、キーのビューを返すlist(d.keys())ためdict.keys、使用することが重要です。Python2を使用している場合は、これで十分です。d.keys()


1

ハナンの答えは、より一般的なケースをカバーしているので正しい答えです(他の答えは、重複した状況を知らない人を誤解させるようなものです)。ハナンの答えの改善は、setdefaultを使用することです:

mydict = {1:a, 2:a, 3:b}   
result = {}
for i in mydict:  
   result.setdefault(mydict[i],[]).append(i)
print(result)
>>> result = {a:[1,2], b:[3]}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.