次のような辞書があるとします。
my_map = {'a': 1, 'b': 2}
このマップを反転して取得するにはどうすればよいですか。
inv_map = {1: 'a', 2: 'b'}
次のような辞書があるとします。
my_map = {'a': 1, 'b': 2}
このマップを反転して取得するにはどうすればよいですか。
inv_map = {1: 'a', 2: 'b'}
Python 3+:
inv_map = {v: k for k, v in my_map.items()}
パイソン 2:
inv_map = {v: k for k, v in my_map.iteritems()}
dict の値が一意であると仮定します。
パイソン 3:
dict((v, k) for k, v in my_map.items())
パイソン 2:
dict((v, k) for k, v in my_map.iteritems())
の値my_map
が一意でない場合:
Python 3:
inv_map = {}
for k, v in my_map.items():
inv_map[v] = inv_map.get(v, []) + [k]
Python 2:
inv_map = {}
for k, v in my_map.iteritems():
inv_map[v] = inv_map.get(v, []) + [k]
dict
マッピングのタイプを保持しながらこれを行うには (それがまたはdict
サブクラスであると仮定します):
def inverse_mapping(f):
return f.__class__(map(reversed, f.items()))
これを試して:
inv_map = dict(zip(my_map.values(), my_map.keys()))
(ディクショナリ ビューに関する Python ドキュメントでは、要素が同じ順序であることが明示的に保証されていること.keys()
に注意してください.values()
。これにより、上記のアプローチが機能します。)
または:
inv_map = dict((my_map[k], k) for k in my_map)
またはpython 3.0のdict内包表記を使用する
inv_map = {my_map[k] : k for k in my_map}
これはRobert による回答を拡張し、dict の値が一意でない場合に適用されます。
class ReversibleDict(dict):
def reversed(self):
"""
Return a reversed dict, with common values in the original dict
grouped into a list in the returned dict.
Example:
>>> d = ReversibleDict({'a': 3, 'c': 2, 'b': 2, 'e': 3, 'd': 1, 'f': 2})
>>> d.reversed()
{1: ['d'], 2: ['c', 'b', 'f'], 3: ['a', 'e']}
"""
revdict = {}
for k, v in self.iteritems():
revdict.setdefault(v, []).append(k)
return revdict
reversed
実装は、2 回使用して元に戻すことができないという点で制限されています。それ自体は対称ではありません。Python 2.6 でテストされています。結果の辞書を印刷するために私が使用している方法の使用例を次に示します。
set
aよりも aを使用したい場合でlist
、これが理にかなっている順序付けられていないアプリケーションが存在する可能性がある場合は、 の代わりにsetdefault(v, []).append(k)
を使用しますsetdefault(v, set()).add(k)
。
リスト内包表記と辞書内包表記の組み合わせ。重複キーを処理できます
{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
多くの回答がありますが、一意でない値を持つ辞書について話している場合に備えて、きれいなものは見つかりませんでした。
解決策は次のとおりです。
from collections import defaultdict
inv_map = defaultdict(list)
for k, v in my_map.items():
inv_map[v].append(k)
初期辞書の場合my_map = {'c': 1, 'd': 5, 'a': 5, 'b': 10}
次に、上記のコードを実行すると、次のようになります。
{5: ['a', 'd'], 1: ['c'], 10: ['b']}
これを行う最善の方法は、クラスを定義することだと思います。「対称辞書」の実装は次のとおりです。
class SymDict:
def __init__(self):
self.aToB = {}
self.bToA = {}
def assocAB(self, a, b):
# Stores and returns a tuple (a,b) of overwritten bindings
currB = None
if a in self.aToB: currB = self.bToA[a]
currA = None
if b in self.bToA: currA = self.aToB[b]
self.aToB[a] = b
self.bToA[b] = a
return (currA, currB)
def lookupA(self, a):
if a in self.aToB:
return self.aToB[a]
return None
def lookupB(self, b):
if b in self.bToA:
return self.bToA[b]
return None
削除および反復メソッドは、必要に応じて簡単に実装できます。
この実装は、辞書全体を反転するよりもはるかに効率的です (これは、このページで最も一般的なソリューションのようです)。言うまでもなく、SymDict の値を好きなだけ追加または削除でき、逆辞書は常に有効なままです。これは、辞書全体を一度逆にするだけでは当てはまりません。
上で提案した他の関数に加えて、ラムダが好きなら:
invert = lambda mydict: {v:k for k, v in mydict.items()}
または、次の方法でも実行できます。
invert = lambda mydict: dict( zip(mydict.values(), mydict.keys()) )
値が一意ではなく、少し筋金入りの場合:
inv_map = dict(
(v, [k for (k, xx) in filter(lambda (key, value): value == v, my_map.items())])
for v in set(my_map.values())
)
特に大きな dict の場合、このソリューションは、複数回ループするため、Python の逆/反転マッピングよりもはるかに効率が悪いことに注意してください。items()
非全単射マップ (値が一意ではない) の高速関数ソリューション:
from itertools import imap, groupby
def fst(s):
return s[0]
def snd(s):
return s[1]
def inverseDict(d):
"""
input d: a -> b
output : b -> set(a)
"""
return {
v : set(imap(fst, kv_iter))
for (v, kv_iter) in groupby(
sorted(d.iteritems(),
key=snd),
key=snd
)
}
理論的には、これは命令型ソリューションのように 1 つずつセットに追加 (またはリストに追加) するよりも高速です。
残念ながら、値はソート可能でなければなりません。ソートは groupby で必要です。
ディクショナリは、値とは異なり、ディクショナリ内に 1 つの一意のキーを必要とするため、逆の値を並べ替えのリストに追加して、新しい特定のキーに含める必要があります。
def r_maping(dictionary):
List_z=[]
Map= {}
for z, x in dictionary.iteritems(): #iterate through the keys and values
Map.setdefault(x,List_z).append(z) #Setdefault is the same as dict[key]=default."The method returns the key value available in the dictionary and if given key is not available then it will return provided default value. Afterward, we will append into the default list our new values for the specific key.
return Map
これをpython 2.7/3.xで試してください
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
関数はリスト型の値に対して対称的です。reverse_dict(reverse_dict(dictionary)) を実行すると、タプルはリストに変換されます
def reverse_dict(dictionary):
reverse_dict = {}
for key, value in dictionary.iteritems():
if not isinstance(value, (list, tuple)):
value = [value]
for val in value:
reverse_dict[val] = reverse_dict.get(val, [])
reverse_dict[val].append(key)
for key, value in reverse_dict.iteritems():
if len(value) == 1:
reverse_dict[key] = value[0]
return reverse_dict
私はpython 2でそのようにします。
inv_map = {my_map[x] : x for x in my_map}
値が一意ではなく、かつハッシュ (1 次元) の可能性がある場合:
for k, v in myDict.items():
if len(v) > 1:
for item in v:
invDict[item] = invDict.get(item, [])
invDict[item].append(k)
else:
invDict[v] = invDict.get(v, [])
invDict[v].append(k)
さらに深く掘り下げる必要がある場合は、再帰を使用して、1 つのディメンションのみを使用します。
def digList(lst):
temp = []
for item in lst:
if type(item) is list:
temp.append(digList(item))
else:
temp.append(item)
return set(temp)
for k, v in myDict.items():
if type(v) is list:
items = digList(v)
for item in items:
invDict[item] = invDict.get(item, [])
invDict[item].append(k)
else:
invDict[v] = invDict.get(v, [])
invDict[v].append(k)
サイクル「for」とメソッド「.get()」を使ってこれを書き、「map」は関数であるため、辞書の名前「map」を「map1」に変更しました。
def dict_invert(map1):
inv_map = {} # new dictionary
for key in map1.keys():
inv_map[map1.get(key)] = key
return inv_map