How to count occurrence of strings within a dictionary made up of lists in Python?

Asked

Viewed 361 times

1

I have a satisfaction research dictionary that the evaluator can evaluate up to 6 products. The program stores the evaluator, the refrigerant and the note for the refrigerant.

And I have to show the names of the appraisers and the quantity of products assessed individually.

pesquisa = {'PEDRO': ['FANTA',5,'PEPSI',4],'ANA': ['SPRITE',5,'COCACOLA,4]}

def relatorio_avaliadores():
    print('Relatório de Avaliadores')

    for nome in sorted(pesquisa.keys()):
        
    print(f'{nome} avaliou o total de, , produto(s).')

How can I count the number of soft drinks that has been evaluated by each person?

4 answers

2

If this is always the format of the counts you can also:

pesquisa = {'PEDRO': ['FANTA',5,'PEPSI',4],'ANA': ['SPRITE',5,'COCACOLA',4], 'DIEGO': ['INTEL', 7, 'PYTHON', 8, 'WINDOWS', 9, 'LINUX', 10]}
c = {i: sum((1 for j in pesquisa[i][::2])) for i in pesquisa}
print(c) # {'PEDRO': 2, 'DIEGO': 4, 'ANA': 2}

DEMONSTRATION

2


Specifically speaking of your answer, len already returns an integer, then do int(len(etc...)) is redundant and unnecessary. Do only count = len(pesquisa[nome]) // 2 would be enough (using the entire split operator // so that the result is not a float).

But actually dividing by 2 seems to me a little "gambiarra", to circumvent the fact that you are using a list, which does not seem to be the most appropriate structure for this case. If the idea is to have a note for each soda, I think it’s best to use a dictionary that maps the name of each soda with its respective note. It may seem a silly detail ("ah, but with lists it works"), but choosing the right data structure is halfway towards better code.

Then I’d do it this way:

def relatorio_avaliadores(pesquisa):
    print('Relatório de Avaliadores')
    for nome in sorted(pesquisa):
        print(f'{nome} avaliou o total de {len(pesquisa[nome])} produto(s).')

# as notas ficam em outro dicionário
pesquisa = {
  'PEDRO': { 'FANTA': 5, 'PEPSI': 4 }, # cada refrigerante é mapeado para sua nota
  'ANA': { 'SPRITE': 5, 'COCACOLA': 4 }
}

relatorio_avaliadores(pesquisa)

Note that to sort the keys, I can simply do sorted(pesquisa). And if I just want to print the quantity and I won’t use this value for anything else, nor would I need the variable cont.

And now I don’t have to divide by two anymore, because according to the documentation, the len of a dictionary returns the number of keys of this, and how each key corresponds to a soda evaluated by the person, when using len(pesquisa[nome]) I’ll have the right value.

Another detail is that the way you did it, the function relatorio_avaliadores only worked for the dictionary pesquisa raised out of it. But now I’ve changed the function to receive the dictionary as a parameter, so it works for any other dictionary that has the same structure. Ex:

from operator import itemgetter

def relatorio_avaliadores(pesquisa):
    print('Relatório de Avaliadores')
    # apenas para mostrar outra forma de iterar pelo dicionário
    for nome, notas in sorted(pesquisa.items(), key=itemgetter(0)):
        print(f'{nome} avaliou o total de {len(notas)} produto(s).')

# dados de uma pesquisa
pesquisa1 = {
  'PEDRO': { 'FANTA': 5, 'PEPSI': 4 },
  'ANA': { 'SPRITE': 5, 'COCACOLA': 4 }
}
relatorio_avaliadores(pesquisa1)

# dados de outra pesquisa
pesquisa2 = {
  'Fulano': { 'FANTA': 5, 'PEPSI': 4 },
  'Ciclano': { 'SPRITE': 5, 'COCACOLA': 4, 'TUBAÍNA': 5 },
  'Beltrano': {},
  'Trajano': { 'GUARANÁ': 3, 'FANTA': 2, 'PEPSI': 1, 'COCACOLA': 4 }
}
relatorio_avaliadores(pesquisa2)

# posso inclusive passar o dicionário diretamente
relatorio_avaliadores({
  'Maria': { 'FANTA': 3 },
  'José': { 'COCACOLA': 5, 'SPRITE': 2 },
  'Fulano': { 'GUARANÁ': 4, 'PEPSI': 2, 'COCACOLA': 4 }
})

Note that I can pass any dictionary to the function, and it works the same way (so it gets more generic, rather than depending on an external variable to it).

I also showed another way to iterate through the dictionary, returning the name and notes at the same time, and sorting through the key: items() returns keys and values in tuples, and in the sort I say to use the first element of the tuple, which is the dictionary key (use itemgetter(0) to indicate that I will use the first element - remember that the indexes start at zero, so I used itemgetter(0)).


And as recalled in the comments, if you don’t have control over the structure, you can convert its initial structure to the one I suggested above:

pesquisa = {'PEDRO': ['FANTA',5,'PEPSI',4],'ANA': ['SPRITE',5,'COCACOLA',4]}
pesquisa = { nome: dict(zip(notas[::2], notas[1::2])) for nome, notas in pesquisa.items() }

That is, for each reviewer, I take the list of notes and turn it into the dictionary. The trick is to use the Slices [::2] (takes the even indexes of the list) and [1::2] (picks up the odd indices). Read here to better understand how this syntax works.

  • 1

    It is worth saying how to convert into dict, since we don’t know if it’s in control of the AP, anything like: d = {i: dict(zip(pesquisa[i][::2], pesquisa[i][1::2])) for i in pesquisa}

  • @Miguel Boa, updated the reply, thank you!

  • 1

    You’re welcome @hkotsubo (:

0

I managed to solve it! I’m a beginner and still use basic things to solve my problems, if you know in a more pytonic way I accept suggestions!

def relatorio_avaliadores():
    print('Relatório de Avaliadores')

    for nome in sorted(pesquisa.keys()):
        count = int(len(pesquisa[nome])/2)
        
        print(f'{nome} avaliou o total de, {count}, produto(s).')

0

In case you don’t want to split it two ways, like you did here:

pesquisa = {'PEDRO': ['FANTA',5,'PEPSI',4],'ANA': ['SPRITE',5,'COCACOLA',4]}

def relatorio_avaliadores():
    print('Relatório de Avaliadores')

    for nome in sorted(pesquisa.keys()):
        count = int(len(pesquisa[nome])/2)
        
        print(f'{nome} avaliou o total de, {count}, produto(s).')

You can iterate using list comprehension and see which ones are str with isinstance:

pesquisa = {'PEDRO': ['FANTA',5,'PEPSI',4],'ANA': ['SPRITE',5,'COCACOLA',4]}

def relatorio_avaliadores():
    print('Relatório de Avaliadores')

    for nome, avaliacoes in sorted(pesquisa.items()):
        count = len([i for i in avaliacoes if isinstance(i, str)])
        print(f'{nome} avaliou o total de, {count} produto(s).')

You can do it with the filter too:

count = len(list(filter(lambda x : isinstance(x, str), avaliacoes)))

This way it will only count when you find something in the format 'string'.

Browser other questions tagged

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