20

I would like 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 as explained below:

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

to

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

The list of values in the returned dictionary should be sorted in ascending order. Capitalization does not matter. This means that all the words should be converted to lower case letters. For example the word "Accurate" is capitalized in the original dictionary but in the returned dictionary it is written with all lower case letters.

#My code is:
from collections import defaultdict
def reverse_dictionary(input_dict):
   d = defaultdict(list)
   for v,k in input_dict.items():
       d[k].append(v)
       return d

But it returns this error though:

Error in evaluating function:
TypeError at line 6
unhashable type: 'list'
6
  • 3
    The problem is that you cannot use any object as a key -- these objects must be immutable so their hash value does not change after they're added to the dictionary. In your case, lists are mutable, so they cannot be used as keys. You could convert them to tuples instead. Commented Mar 11, 2016 at 16:42
  • 2
    Welcome to StackExchange! It might be helpful to give more thought to this problem. For example, why would 'Accurate': ['exact', 'precise'] become 'precise': ['accurate', 'exact'] instead of 'exact': ['accurate', 'precise']? As far as your error message is concerned, a list cannot be your dict key, but I think the bigger problem is that you task needs to be clarified. Commented Mar 11, 2016 at 16:44
  • Also, dictionaries cannot be sorted.
    – Farhan.K
    Commented Mar 11, 2016 at 16:46
  • 1
    @FrédéricHamidi He is trying to use strings as keys, not lists. He just isn't doing it right.
    – zondo
    Commented Mar 11, 2016 at 16:57
  • Seems pretty clear to me. The content of the values become the keys, and the keys get added to the values, so {'a': ['b', 'c']} becomes {'b': ['a'], 'c': ['a']}. @DanielStandage, @SteinarLima Commented Mar 11, 2016 at 17:00

5 Answers 5

16

You can do it very simply like this:

newdict = {}
for key, value in olddict.items():
    for string in value:
        newdict.setdefault(string, []).append(key)
5
  • Always, always, always use dict comprehensions when the chance arises :) Commented Mar 11, 2016 at 16:59
  • Can you give an example? I just couldn't think of one that would work.
    – zondo
    Commented Mar 11, 2016 at 17:01
  • Oh, oops - I thought that's what you'd done, I was being dumb. I wasn't trying to be condescending but I realize that's exactly how I came off, apologies Commented Mar 11, 2016 at 17:02
  • Nuts. I was hoping you could come up with one ;) I took out the list comprehension because it really shouldn't be used.
    – zondo
    Commented Mar 11, 2016 at 17:04
  • I still appreciated it nonetheless :) Commented Mar 11, 2016 at 17:04
5

I would begin by swapping the keys/values using a default dict:

output_dict = defaultdict(list)
for key, values in input_dict.items():
    for value in values:
        output_dict[value.lower()].append(key.lower())

And finally sorting:

for key, values in output_dict.items():
    output_dict[key] = sorted(values)
1

Use a dict comprehension!

>>> evil_petting_zoo = {'bear':3, 'crocodile':1,'kangaroo':2,'goat':0}
>>> evil_petting_zoo.items()

dict_items([('bear', 3), ('crocodile', 1), ('kangaroo', 2), ('goat', 0)])

>>> {i[1]:i[0] for i in evil_petting_zoo.items()}

{3: 'bear', 1: 'crocodile', 2: 'kangaroo', 0: 'goat'}

TL;DR:

{i[1]:i[0] for i in myDictionary.items()}
1
  • 1
    That's not what the question asked. It asks for the case when the value is a list. Commented Sep 6, 2021 at 21:52
1

For the love of functional programming, here’s fun way:

from itertools import product
from more_itertools import map_reduce, flatten

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

value_key_pairs = flatten(product(v,(k,)) for k,v in olddict.items())
out = map_reduce(value_key_pairs, lambda k:k[0].lower(), lambda k:k[1].lower())

assert dict(out) == {'exact': ['accurate'], 'precise': ['accurate', 'exact'], 'smart': ['astute'], 'clever': ['astute', 'smart'], 'bright': ['smart'], 'talented': ['smart']}

-2

How I reverse a dict:

def reverse(org):
    return {v: k for k, v in org.items()}

print(reverse({1: 'a', 2: 'b'}))
# {'a': 1, 'b': 2}
2
  • this answer is best suited to my problem (and for a standard key:value dict). Thanks ;) Commented Nov 19, 2017 at 10:09
  • This doesn't work if the dictionary values are lists (as in the question).
    – mkrieger1
    Commented Feb 13, 2023 at 14:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.