こんな辞書があるとします。
my_map = { 'a': 1, 'b':2 }
どのようにして得るためにこのマップを反転することができます:
inv_map = { 1: 'a', 2: 'b' }
編集者メモ: map
は組み込み関数map
との衝突を避けるためにmy_map
に変更されました。いくつかのコメントは以下に影響されるかもしれません。
Python 2.7.xの場合
inv_map = {v: k for k, v in my_map.iteritems()}
Python 3+の場合:
inv_map = {v: k for k, v in my_map.items()}
辞書の値は一意であると仮定します。
dict((v, k) for k, v in my_map.iteritems())
my_map
の値が一意ではない場合:
inv_map = {}
for k, v in my_map.iteritems():
inv_map[v] = inv_map.get(v, [])
inv_map[v].append(k)
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の辞書内包表記を使う
inv_map = {my_map[k] : k for k in my_map}
もう1つの、より機能的な方法:
my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
これは、 Pythonがマッピングを反転/反転させる という答えに拡張され、辞書の値が一意でない場合に適用されます。
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
より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()}
私の2セントのPythonic方式を追加する:
inv_map = dict(map(reversed, my_map.items()))
例:
In [7]: my_map
Out[7]: {1: 'one', 2: 'two', 3: 'three'}
In [8]: inv_map = dict(map(reversed, my_map.items()))
In [9]: inv_map
Out[9]: {'one': 1, 'three': 3, 'two': 2}
defaultdict
を使って、重複キーを持つ辞書を逆にすることもできます。
from collections import Counter, defaultdict
def invert_dict(d):
d_inv = defaultdict(list)
for k, v in c.items():
d_inv[v].append(k)
return d_inv
text = 'aaa bbb ccc ddd aaa bbb ccc aaa'
c = Counter(text.split()) # Counter({'aaa': 3, 'bbb': 2, 'ccc': 2, 'ddd': 1})
dict(invert_dict(c)) # {1: ['ddd'], 2: ['bbb', 'ccc'], 3: ['aaa']}
ここ を見てください:
このテクニックは
dict.setdefault()
を使った同等のテクニックより簡単で速いです。
値が一意ではなく、あなたがちょっとハードコアであるなら:
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())
)
特に大規模な辞書では、この解決法は答えよりもはるかに効率が悪いことに注意してください。 Pythonはマッピングを反転/反転します それはitems()
を複数回ループするためです。
あなたがラムダが好きなら、上で提案された他の機能に加えて:
invert = lambda mydict: {v:k for k, v in mydict.items()}
あるいは、このようにしても可能です。
invert = lambda mydict: dict( Zip(mydict.values(), mydict.keys()) )
これは一意でない値を処理し、一意のケースの外観の大部分を保持します。
inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}
Python 3.xでは、 itervalues を values に置き換えます。私はこれを信用することはできません...それはアイコンジャックによって示唆されました。
Zip を使う
inv_map = dict(Zip(my_map.values(), my_map.keys()))
これを行う最善の方法はクラスを定義することです。これが「対称辞書」の実装です。
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には必要に応じて値を追加または削除できます。逆辞書は常に有効なままになります - 単に辞書全体を一度反転しただけではそうはなりません。
たとえば、次のような辞書があります。
dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}
そして、あなたはそのような逆の形でそれを取得したいです。
inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}
最初の解決策 。辞書の key-value ペアを反転するには、for
loopというアプローチを使用します。
# Use this code to invert dictionaries that have non-unique values
inverted_dict = dictio()
for key, value in dict.items():
inverted_dict.setdefault(value, list()).append(key)
第二の解決策 。反転には 辞書内包表記 を使用します。
# Use this code to invert dictionaries that have unique values
inverted_dict = {value: key for key, value in dict.items()}
第三の解決策 。 反転を元に戻す アプローチを使用します。
# Use this code to invert dictionaries that have lists of values
dict = {value: key for key in inverted_dict for value in my_map[key]}
def invertDictionary(d):
myDict = {}
for i in d:
value = d.get(i)
myDict.setdefault(value,[]).append(i)
return myDict
print invertDictionary({'a':1, 'b':2, 'c':3 , 'd' : 1})
これにより、出力が提供されます。{1:['a'、 'd']、2:['b']、3:['c']}
def reverse_dictionary(input_dict):
out = {}
for v in input_dict.values():
for value in v:
if value not in out:
out[value.lower()] = []
for i in input_dict:
for j in out:
if j in map (lambda x : x.lower(),input_dict[i]):
out[j].append(i.lower())
out[j].sort()
return out
このコードは次のようになります。
r = reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})
print(r)
{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
私はpython 2でそのようにします。
inv_map = {my_map[x] : x for x in my_map}
Python 2.7/3.xでこれを試してください。
inv_map={};
for i in my_map:
inv_map[my_map[i]]=i
print inv_map
あなたの辞書を逆にする:
dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}
print(inversed_dict_["v1"])
関数はリスト型の値に対して対称です。逆辞書を実行すると、タプルはリストに変換されます(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
値が一意ではなく、かつハッシュ(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)
そして再帰的にあなたがより深く掘り下げる必要があるならばただ一つの次元:
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)
質問への私のコメントに従って。私は、Python 2とPython 3の両方に使える最も簡単で一つのライナーは、
dict(Zip(inv_map.values(), inv_map.keys()))
辞書は値とは異なり、辞書内に一意のキーを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
まったく違うものではなく、Cookbookのレシピを少し書き直しただけです。インスタンスを通過させるたびにsetdefault
メソッドを保持することで、さらに最適化されます。
def inverse(mapping):
'''
A function to inverse mapping, collecting keys with simillar values
in list. Careful to retain original type and to be fast.
>> d = dict(a=1, b=2, c=1, d=3, e=2, f=1, g=5, h=2)
>> inverse(d)
{1: ['f', 'c', 'a'], 2: ['h', 'b', 'e'], 3: ['d'], 5: ['g']}
'''
res = {}
setdef = res.setdefault
for key, value in mapping.items():
setdef(value, []).append(key)
return res if mapping.__class__==dict else mapping.__class__(res)
CPython 3.xで実行するように設計されています。2.xではmapping.items()
をmapping.iteritems()
に置き換えます。
私のマシンでは、他の例よりも少し速く実行されます。