code

사전 매핑 반전 / 반전

codestyles 2020. 10. 3. 10:43
반응형

사전 매핑 반전 / 반전


다음과 같은 사전이 주어집니다.

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

이지도를 어떻게 뒤집어 다음을 얻을 수 있습니까?

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

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의 값이 고유하다고 가정합니다.

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)

매핑 유형을 유지하면서이를 수행하려면 ( 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 comprehensions 사용

inv_map = {my_map[k] : k for k in my_map}

더 기능적인 또 다른 방법 :

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

이것은 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두 번 사용 하여 원본을 되 찾을 수 없다는 점에서 제한 됩니다. 따라서 대칭이 아닙니다. Python 2.6으로 테스트되었습니다. 다음 은 결과 dict를 인쇄하는 데 사용하는 사용 사례입니다.

당신이 오히려를 사용하는 거라고 경우 set(A)보다 list,이 대신에, 의미가있는 정렬되지 않은 응용 프로그램이 존재할 수 setdefault(v, []).append(k), 사용 setdefault(v, set()).add(k).


다음을 사용하여 중복 키로 사전을 반전 할 수도 있습니다 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().


목록과 사전 이해의 조합. 중복 키 처리 가능

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

값이 고유하지 않고 약간 하드 코어 한 경우 :

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()입니다.


위에서 제안한 다른 기능 외에도 람다를 좋아한다면 :

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

또는 다음과 같이 할 수도 있습니다.

invert = lambda mydict: dict( zip(mydict.values(), mydict.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에서 원하는만큼 값을 추가하거나 제거 할 수 있으며 역사 전은 항상 유효하게 유지됩니다. 단순히 전체 사전을 한 번만 뒤집 으면 사실이 아닙니다.


For instance, you have the following dictionary:

dict = {'a': 'fire', 'b': 'ice', 'c': 'fire', 'd': 'water'}

And you wanna get it in such an inverted form:

inverted_dict = {'fire': ['a', 'c'], 'ice': ['b'], 'water': ['d']}

First Solution. For inverting key-value pairs in your dictionary use a for-loop approach:

# 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)

Second Solution. Use a dictionary comprehension approach for inversion:

# Use this code to invert dictionaries that have unique values

inverted_dict = {value: key for key, value in dict.items()}

Third Solution. Use reverting the inversion approach:

# 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]}

This handles non-unique values and retains much of the look of the unique case.

inv_map = {v:[k for k in my_map if my_map[k] == v] for v in my_map.itervalues()}

For Python 3.x, replace itervalues with values.


Function is symmetric for values of type list; Tuples are coverted to lists when performing 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

Since dictionaries require one unique key within the dictionary unlike values, we have to append the reversed values into a list of sort to be included within the new specific keys.

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

Try this for python 2.7/3.x

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

Fast functional solution for non-bijective maps (values not unique):

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
        )
    }

In theory this should be faster than adding to the set (or appending to the list) one by one like in the imperative solution.

Unfortunately the values have to be sortable, the sorting is required by groupby.


I would do it that way in python 2.

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

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})

This will provide output as : {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

this code do like this:

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

Not something completely different, just a bit rewritten recipe from Cookbook. It's futhermore optimized by retaining setdefault method, instead of each time getting it through the instance:

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)

Designed to be run under CPython 3.x, for 2.x replace mapping.items() with mapping.iteritems()

On my machine runs a bit faster, than other examples here


I wrote this with the help of cycle 'for' and method '.get()' and I changed the name 'map' of the dictionary to 'map1' because 'map' is a function.

def dict_invert(map1):
    inv_map = {} # new dictionary
    for key in map1.keys():
        inv_map[map1.get(key)] = key
    return inv_map

If values aren't unique AND may be a hash (one dimension):

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)

And with a recursion if you need to dig deeper then just one dimension:

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)

참고URL : https://stackoverflow.com/questions/483666/reverse-invert-a-dictionary-mapping

반응형