web-dev-qa-db-ja.com

Pythonはマッピングを反転/反転する

こんな辞書があるとします。

my_map = { 'a': 1, 'b':2 }

どのようにして得るためにこのマップを反転することができます:

inv_map = { 1: 'a', 2: 'b' }

編集者メモ: mapは組み込み関数mapとの衝突を避けるためにmy_mapに変更されました。いくつかのコメントは以下に影響されるかもしれません。

531
Brian M. Hunt

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()}
743
SilentGhost

辞書の値は一意であると仮定します。

dict((v, k) for k, v in my_map.iteritems())
165
unbeknown

my_mapの値が一意ではない場合:

inv_map = {}
for k, v in my_map.iteritems():
    inv_map[v] = inv_map.get(v, [])
    inv_map[v].append(k)
113
Robert Rossney
def inverse_mapping(f):
    return f.__class__(map(reversed, f.items()))
39
fs.

これを試して:

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}
31
sykora

もう1つの、より機能的な方法:

my_map = { 'a': 1, 'b':2 }
dict(map(reversed, my_map.items()))
18
Brendan Maguire

これは、 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)を使用してください。

7
A-B-B

リストと辞書の理解の組み合わせ。重複キーを処理できます

{v:[i for i in d.keys() if d[i] == v ] for k,v in d.items()}
7
SVJ

私の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}
5
Amit Kushwaha

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()を使った同等のテクニックより簡単で速いです。

5
irudyak

値が一意ではなく、あなたがちょっとハードコアであるなら:

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()を複数回ループするためです。

4
pcv

あなたがラムダが好きなら、上で提案された他の機能に加えて:

invert = lambda mydict: {v:k for k, v in mydict.items()}

あるいは、このようにしても可能です。

invert = lambda mydict: dict( Zip(mydict.values(), mydict.keys()) )
3
RussellStewart

これは一意でない値を処理し、一意のケースの外観の大部分を保持します。

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 に置き換えます。私はこれを信用することはできません...それはアイコンジャックによって示唆されました。

3
Ersatz Kwisatz

Zip を使う

inv_map = dict(Zip(my_map.values(), my_map.keys()))
2
Kwaw Annor

これを行う最善の方法はクラスを定義することです。これが「対称辞書」の実装です。

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には必要に応じて値を追加または削除できます。逆辞書は常に有効なままになります - 単に辞書全体を一度反転しただけではそうはなりません。

2
NcAdams

たとえば、次のような辞書があります。

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]}
2
ARGeo
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']}

1
RVR
  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']}
1
Shb8086

私はpython 2でそのようにします。

inv_map = {my_map[x] : x for x in my_map}
1
genghiscrade

Python 2.7/3.xでこれを試してください。

inv_map={};
for i in my_map:
    inv_map[my_map[i]]=i    
print inv_map
1
dhvlnyk

あなたの辞書を逆にする:

dict_ = {"k0":"v0", "k1":"v1", "k2":"v1"}
inversed_dict_ = {val: key for key, val in dict_.items()}

print(inversed_dict_["v1"])
0
Miladiouss

関数はリスト型の値に対して対称です。逆辞書を実行すると、タプルはリストに変換されます(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
0
Alf

値が一意ではなく、かつハッシュ(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)
0
mveith

質問への私のコメントに従って。私は、Python 2とPython 3の両方に使える最も簡単で一つのライナーは、

dict(Zip(inv_map.values(), inv_map.keys()))
0
Seshadri VS

辞書は値とは異なり、辞書内に一意のキーを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
0
EyoelD

まったく違うものではなく、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()に置き換えます。

私のマシンでは、他の例よりも少し速く実行されます。

0
thodnev