Dictionary reordering, exchanging values for keys

Asked

Viewed 918 times

4

I have the following dictionary:

tests_dict = {'test 1': ['Manuel', 'Mariana', 'Filipa'], 'test 2': ['Manuel', 'Filipa', 'Mariana'], 'test 3': ['Mariana', 'Manuel', 'Filipa']}

What I need is for the new dictionary keys to be the names of the people, with the test done and the place (Indice) where the respective name is in the list of the current dictionary, desired format:

peps_dict = {'Manuel': {'test 1': 1, 'test 2': 1, 'test 3': 2}, 'Mariana': {'test 1': 2, 'test 2': 3, 'test 3': 1}, 'Filipa': {'test 1': 3, 'test 2': 2, 'test 3': 3}}

As you can see, Manuel in test 1 was first in test 2 also came first and in test 3 came second, these positions are based on the Index of the lists in the original dictionary, and add 1, because it is a system of rank and there can be below the first place (0 makes no sense)

  • Use indicas starting at 0. If the word is in the first position, your Dice must be "0" and not "1".

  • Yes it is true, this is a rank system is based on the Dice but the 0 is equivalent to the first place, as I put in the desired format. I’ll fix that, sorry for the misunderstanding

  • @jsbueno, I also noticed this, but I followed myself by the format I wanted, because I also thought that was what made sense in this context and by the AP explanation, "... Manuel in test 1 came first..."

  • @Miguel - of course, you have to answer what was asked. But it is worth commenting on the answer, what is the best way to leave the indexes.

  • I agree @jsbueno, of course yes, the clearer the better

1 answer

5


Then we have:

tests_dict = {'test 1': ['Manuel', 'Mariana', 'Filipa'], 'test 2': ['Manuel', 'Filipa', 'Mariana'], 'test 3': ['Mariana', 'Manuel', 'Filipa']}

You can do it like this:


1.

This first way is more didactic, so I think you understand the logic behind this:

peps_dict = {}
for test in tests_dict:
    for indx, name in enumerate(tests_dict[test], 1): # vamos percorrer os nomes e respetivo indice em cada lista, começando em 1
        if name not in peps_dict: # se o nome ainda nao estiver presente como chave no nosso novo dionario
            peps_dict[name] = {} # vamos declara-lo como um dicionario tambem
        peps_dict[name][test] = indx # ex: peps_dict['Manuel']['test 1'] = 1, {'Manuel': {'test 1': 1}}

DEMONSTRATION


2.

In this way we will import defaultdict, which in this case allows us to exclude the verification if name not in peps_dict, this way there is no KeyError in our new dictionary, and each key (name) by default we define to be a dictionary as well:

from collections import defaultdict

peps_dict = defaultdict(dict)
for test in tests_dict:
    for indx, name in enumerate(tests_dict[test], 1):
        peps_dict[name][test] = indx

DEMONSTRATION

An alternative, IN this case, to defaultdict is to use setdefault (Thanks to @Jjoao who reminded me of this in comment), and so also excuses to do the import, this method is only applicable to dictionaries:

peps_dict = {}
for test in tests_dict:
    for indx, name in enumerate(tests_dict[test], 1):
        peps_dict.setdefault(name,{})[test] = indx

Demonstration


3.

This last one I did more for the challenge, the logic changes a little compared to the first one. Let’s go through all the names, join all the names in one list ((name for listN in tests_dict.values() for name in listN)), Generator in this case, and we add each n as being a key to our dictionary, and then via Dict compreension populate them with the corresponding values ({test: tests_dict[test].index(n) + 1}, Let’s get the name in the original list and add 1)

peps_dict = {}
names = (name for listN in tests_dict.values() for name in listN)
for n in names:
    peps_dict[n] = {test: tests_dict[test].index(n) + 1 for test in tests_dict if n in tests_dict[test]}

DEMONSTRATION

The latter may be reduced to:

names = (name for listN in tests_dict.values() for name in listN)
peps_dict = {n: {test: tests_dict[test].index(n) + 1 for test in tests_dict if n in tests_dict[test]} for n in names}

DEMONSTRATION

Output (print(peps_dict)) for the above cases:

{'Manuel': {'test 1': 1, 'test 2': 1, 'test 3': 2}, 'Filipa': {'test 1': 3, 'test 2': 2, 'test 3': 3}, 'Mariana': {'test 1': 2, 'test 2': 3, 'test 3': 1}}

PS: This whole exercise starts from the presuposto that there are no equal names in each list, if there are two "Manuel" in a list the last to be covered will override the first, there can be no equal keys

  • cool! suggestion at first replace the if with peps_dict.setdefault(name,{})


  • 1

    Thanks @Jjoao, I added this alternative in the reply

  • Thank you: I never thought of setdefault(name,{})[...]=...

  • hehe (: @Jjoao , shorter like this

Browser other questions tagged

You are not signed in. Login or sign up in order to post.