Python Forum

Full Version: Swap key and value of a dictionary - and sort it
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

The input is this:

Output:
{'Accurate': ['exact', 'precise'], 'exact': ['precise'], 'astute': ['Smart', 'clever'], 'smart': ['clever', 'bright', 'talented']}
And the output is supposed to be this:
Output:
{'precise': ['accurate', 'exact'], 'clever': ['astute', 'smart'], 'talented': ['smart'], 'bright': ['smart'], 'exact': ['accurate'], 'smart': ['astute']}
Note that values of each key are sorted.

My code is this:

def reverse_dictionary(input_dict):

    my_dict= {}

    for key, value in input_dict.items():
        for string in value:
            my_dict.setdefault(string.lower(), []).append(key.lower())
    
    output_dict={k:v for k,v in sorted(my_dict.items(), key=lambda item:item[1])}

    return output_dict
But this code is not producing the expected result. What am I missing here?
(Oct-27-2020, 03:24 PM)Omid Wrote: [ -> ]Note that values of each key are sorted.

Perhaps I am missing something, but it appears to me that the values of each key are sorted correctly when I compare the output of your code to the desired output. The only values that can be sorted are those of 'precise' and 'clever', since they are the only keys that have more than one value.

The keys in your returned dictionary are not sorted in the same way as the desired output, but you didn't mention anything about how the keys are to be sorted. For each key in your code's output, the values appear to be the same (and sorted in the same way) as those in the desired output. If I am missing something, please let me know. Think
What you are missing is what determines the order of the output dictionary. I am missing it too. precise and clever are the first two keys. Is that because they have the most values? But why is talented next?

It took me a while to find a combination of conditions to give me the order precise, clever, talented, bright, exact and smart. I counted letters and computed sums of the ordinal values and looked at sorting based on the values and on particular letters in the values. exact and smart were the most difficult for me.
I got precise, clever, talented, bright, smart and exact fairly early. The sorting key is so bizarre looking that I know there has to be something more direct.
It was just the wrong index. Use index 0 if you want to sort by keys and if you use 1, you're sorting by values.

If you sort by keys, you should get this order:
In [45]: sorted("precise clever talented bright smart exact".split())
Out[45]: ['bright', 'clever', 'exact', 'precise', 'smart', 'talented']
For example, you can sort your str also by length:
In [46]: sorted("precise clever talented bright smart exact".split(), key=len)
Out[46]: ['smart', 'exact', 'clever', 'bright', 'precise', 'talented']
Now back to your code:
def reverse_dictionary(input_dict):
    my_dict= {}
    for key, value in input_dict.items():
        for string in value:
            my_dict.setdefault(string.lower(), []).append(key.lower())
    output_dict={k:v for k,v in sorted(my_dict.items(), key=lambda item:item[0])} # not index 1, index 0 is the key
    return output_dict


# first iteration
from operator import itemgetter


def reverse_dictionary(input_dict):
    result = {}
    by_key = itemgetter(0)
    for key, values in input_dict.items():
        for string in values:
            result.setdefault(string.lower(), []).append(key.lower())
    return dict(sorted(result.items(), key=by_key))


# second iteration
from collections import defaultdict
from operator import itemgetter


def reverse_dictionary(input_dict):
    result = defaultdict(list)
    by_key = itemgetter(0)
    for key, values in input_dict.items():
        for string in values:
            result[string.lower()].append(key.lower())
    return dict(sorted(result.items(), key=by_key))


# third iteration
from collections import defaultdict
from operator import itemgetter


def sort_dict_keys(mapping):
    return dict(sorted(result.items(), key=itemgetter(0)))


def reverse_dictionary(input_dict):
    result = defaultdict(list)
    for key, values in input_dict.items():
        for string in values:
            result[string.lower()].append(key.lower())
    return sort_dict_keys(result)
If you have a predefined order, you could use a mapping to int.
Predefined order:
def custom_order(key_value, default=0):
    key, _ = key_value
    key_order = {
        "bright": 1,
        "clever": 2,
        "exact": 100,
        "precise": 3,
        "smart": 4,
        "talented": 5,
    }
    return key_order.get(key, default)
It's not the best example because the dict was defined inside the function.
But I hope it helps to clarify that you can do also custom sort order.
Dears,

Thank you so much for taking time to reply my question. It appears that the instructions were confusing and my code was indeed correct.

Regards
Omid