Reverse Dictionary. Output keeps changing
Question: So I have to write a function that receives a dictionary as input argument and
returns a reverse of the input dictionary where the values of the original
dictionary are used as keys for the returned dictionary and the keys of the
original dictionary are used as value for the returned dictionary.

For example, if the function is called as

    
    
    reverse_dictionary({'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']})
    

then my function should return

    
    
    {'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
    

Here's my function

    
    
    def reverse_dictionary(input_dict):
        d={}
        def countEmpty(dictionario):
            count=0
            for k,v in dictionario.items():
                if(len(dictionario[k])==0):
                    count+=1
            return count
        def removo(dicto, dicto2):
            for k,v in dicto.items():
                #v.sort()
                if (len(dicto[k])!=0):
                    if v[-1] not in dicto2:
                        dicto2[v[-1].lower()]=[k.lower()]
                    else:
                        dicto2[v[-1]].append(k.lower())
                    dicto[k]=v[:-1]
        while countEmpty(input_dict)<len(input_dict):
            removo(input_dict,d)
        for k,v in d.items():
            v.sort()
        return d
    
    dicta={'astute': ['Smart', 'clever', 'talented'], 'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'talented': ['smart', 'keen', 'Bright'], 'smart': ['clever', 'bright', 'talented']}
    print(reverse_dictionary(dicta))
    

The program initially works. It reverses the dictionary. But the values in the
dictionary need to be sorted. I've tested the program with:

    
    
    dicta={'astute': ['Smart', 'clever', 'talented'], 'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'talented': ['smart', 'keen', 'Bright'], 'smart': ['clever', 'bright', 'talented']}
    

And it sometimes returns:

    
    
    {'keen': ['talented'], 'talented': ['astute', 'smart'], 'clever': ['astute', 'smart'], 'exact': ['accurate'], 'bright': ['smart', 'talented'], 'precise': ['accurate', 'exact'], 'smart': ['astute', 'talented']}
    

Which is the correct answer, but at times it also returns:

    
    
    {'bright': ['smart', 'talented'], 'exact': ['accurate'], 'talented': ['astute', 'smart'], 'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'smart': ['astute'], 'keen': ['talented']}
    

which has the 'smart' key missing the 'talented' value. Even if I have done
nothing to change the code. I understand dictionaries in python don't really
have any order, but shouldn't the values be consistent? Why does this happen?


Answer: You can make a sorted list of tuples associating each value with its key in
the original dict, then use itertools.groupby, dict comprehension and list
comprehesion to merge the output:

    
    
    import itertools
    
    d = {'accurate': ['exact', 'precise'],
         'exact': ['precise'], 
         'astute': ['smart', 'clever'],
         'smart': ['clever', 'bright', 'talented']}
    
    l = sorted([(v2,k) for k, v in d.items() for v2 in v])
    
    {k:list(x[1] for x in g) for k, g in itertools.groupby(l, lambda x: x[0])}
    

Intermediate list l:

    
    
    [('bright', 'smart'),
     ('clever', 'astute'),
     ('clever', 'smart'),
     ('exact', 'accurate'),
     ('precise', 'accurate'),
     ('precise', 'exact'),
     ('smart', 'astute'),
     ('talented', 'smart')]
    

Output:

    
    
    {'bright': ['smart'],
     'clever': ['astute', 'smart'],
     'exact': ['accurate'],
     'precise': ['accurate', 'exact'],
     'smart': ['astute'],
     'talented': ['smart']}
    

