How to create nested and counting dictionaries from lists/tuples?

Asked

Viewed 126 times

1

I have lists of sublists and tuples inside. I need to create a dictionary whose key is the car name and the value is a dictionary nested with the car model count. My lists are like this (it’s just a small example, with partial result I counted in the eye!):

navio_fatiado = [[('Ferrari', 'CONV'), ('Audi', 'SEDAN')],[('Fusca', 'CONV'), ('Limousine', 'VINTAGE')], [('Porsche', 'CONV'), ('Lamborghini', 'CONV')],[('Audi', 'CONV'), ('Fusca', 'CONV')]]

resultado_desejado = {'Ferrari': {'CONV': 1}, 'Audi': {'SEDAN': 1, 'CONV': 1}, 'Fusca': {'CONV': 2}, 'Limousine': {'VINTAGE': 1}}

So far, all I’ve been able to do is this:

from collections import defaultdict        

dicionario_chave = defaultdict(int)
dicionario_valor = defaultdict(int)
  
for linhas in navio_fatiado:    
    for elementos in linhas:
        if not elementos[0] in dicionario_chave:
            dicionario_chave[elementos[0]]
            if elementos[1] in dicionario_valor:
                dicionario_valor[elementos[1]] += 1
            else:
                dicionario_valor[elementos[1]] = 1

I mean, I can only count the values, but I can’t put together the dictionaries with their correct keys, which are the other dictionaries.

Output:

print(dicionario_chave, dicionario_valor) defaultdict(<class 'int'>, {'Ferrari': 0, 'Audi': 0, 'Fusca': 0, 'Limousine': 0, 'Porsche': 0, 'Lamborghini': 0}) defaultdict(<class 'int'>, {'CONV': 4, 'SEDAN': 1, 'VINTAGE': 1})

  • I’m sorry but because I rejected the issue. I was just making the question clearer before submitting an answer.

  • I reversed to a format more suitable to the site.

  • It’s the first time I use the site and I’m learning. I didn’t know I had revisions, and I didn’t agree with all of them. I appreciate your kindness anyway. I will certainly stay tuned in the next.

  • 1

    I’m sorry to sound rude, but I’m just clarifying the text normative site. Understand how the site works by reading What is Stack Overflow. Here are some guidelines that will help you: Stack Overflow Survival Guide in English

  • 1

    Sir, texts like Alguém poderia me ajudar? Obrigado. and Ainda sou iniciante no Python e não consigo resolver um problema. are considered communication noises here on the site. Read the links I passed.

2 answers

3

The idea of the algorithm is to break the structured data passed in the list navio_fatiado in information subunits.

For each item in the list navio_fatiado I imagine you as an object container which is nothing more than a list composed of tuples.
For each of these tuples I imagine you as one veículo whose attributes are brand name and model.

The code starts by defining a dictionary where the resultado.

For each container in navio_fatiado and for each veiculo in that container I check if in the result there is already a key that is the brand name of veiculo:

  • If there is such a key modelo of veiculo and the result in the key whose value is brand name of the vehicle we are one more.
  • Otherwise I create in the resultado a key that is the brand name of veiculo whose value is a.
#Dado estruturado apresentado pelo AP.
navio_fatiado = [
  [('Ferrari', 'CONV'), ('Audi', 'SEDAN')],
  [('Fusca', 'CONV'), ('Limousine', 'VINTAGE')],   
  [('Porsche', 'CONV'), ('Lamborghini', 'CONV')],
  [('Audi', 'CONV'), ('Fusca', 'CONV')]
]

#Aqui será apresentado o resultado.
resultado = {}

#Para cada container em navio_fatiado...
for container in navio_fatiado:
    #Para cada veiculo nesse container...
    for veiculo in container:
        #No resultado ha uma chave que seja a *marca* do `veiculo`?
        if veiculo[0] in resultado:     #Se sim...
            modelo = veiculo[1]                                                      #Extrai o modelo do veiculo.
            resultado[veiculo[0]][modelo] = resultado[veiculo[0]].get(modelo, 0) + 1 #Na chave cujo o valor é marca do veículo some mais um.
            
            
        else:                           #Se não...
            resultado[veiculo[0]] = {                                                 #Crie no resultado uma chave que seja a marca do veiculo cujo valor é um.
                veiculo[1]: 1
             }

print(resultado)

Which results in:

>>> print(resultado)
{
 'Ferrari': {'CONV': 1}, 
 'Audi': {'SEDAN': 1, 'CONV': 1}, 
 'Fusca': {'CONV': 2}, 
 'Limousine': {'VINTAGE': 1}, 
 'Porsche': {'CONV': 1}, 
 'Lamborghini': {'CONV': 1}
}

Execute the code on Python Cloud.

  • 2

    The output is different from what the A.P. requested - see "AUDI" should have two inputs - one for Sedan and one for Conv, with different counts.

  • 2

    simply do modelo = veiculo[1] and use the mercy get from the dictionary to see if that model already exists or not.

  • @jsbueno made the corrections. Thank you.

  • 1

    Very good explanation and resolution. I thank you for the kindness and the time dedicated to helping me. Thank you.

2


No need to complicate creating 2 dictionaries (one with the names and the other with the counts). Do it all at once:

navio_fatiado = [
    [('Ferrari', 'CONV'), ('Audi', 'SEDAN')],
    [('Fusca', 'CONV'), ('Limousine', 'VINTAGE')],
    [('Porsche', 'CONV'), ('Lamborghini', 'CONV')],
    [('Audi', 'CONV'), ('Fusca', 'CONV')]
];

result = {}
for container in navio_fatiado:
    for carro, modelo in container:
        if carro not in result: # carro ainda não está no dicionário
            result[carro] = {}
        if modelo not in result[carro]: # modelo ainda não está no dicionário do carro
            result[carro][modelo] = 1
        else: # modelo já existe, atualiza a contagem
            result[carro][modelo] += 1

print(result)

Note that when going through the tuples that contain the name of the car and model, I can assign the values to variables in the for (in for carro, modelo in container). That is, in the first iteration of the first list, nome will be "Ferrari" and modelo will be "CONV" in the second iteration, nome shall be "Audi" and modelo will be "SEDAN", etc.

Then I’ll see if the car isn’t in the main dictionary yet (if it isn’t, I’ll create an empty dictionary for it).

Then I see if the model is in the dictionary of the car, and if it is not, I put the value 1 (and if it is, we add 1 to the current value).

The result will be:

{'Ferrari': {'CONV': 1}, 'Audi': {'SEDAN': 1, 'CONV': 1}, 'Fusca': {'CONV': 2}, 'Limousine': {'VINTAGE': 1}, 'Porsche': {'CONV': 1}, 'Lamborghini': {'CONV': 1}}

Another alternative to count is to use a Counter:

from collections import Counter

navio_fatiado = [
    [('Ferrari', 'CONV'), ('Audi', 'SEDAN')],
    [('Fusca', 'CONV'), ('Limousine', 'VINTAGE')],
    [('Porsche', 'CONV'), ('Lamborghini', 'CONV')],
    [('Audi', 'CONV'), ('Fusca', 'CONV')]
];

result = {}
for container in navio_fatiado:
    for carro, modelo in container:
        if carro not in result: # carro ainda não está no dicionário
            result[carro] = Counter() # cria um Counter vazio
        result[carro].update([modelo])

print(result)

The idea is similar, the difference is that the Counter already takes care of the details of updating the count of each model.

The exit is a little different:

{'Ferrari': Counter({'CONV': 1}), 'Audi': Counter({'SEDAN': 1, 'CONV': 1}), 'Fusca': Counter({'CONV': 2}), 'Limousine': Counter({'VINTAGE': 1}), 'Porsche': Counter({'CONV': 1}), 'Lamborghini': Counter({'CONV': 1})}

But a Counter is a subclass of dict and so it is also a dictionary and can be used as such (for example, to know how many Ferrari CONV there are, just do result['Ferrari']['CONV']), exactly as you would with dictionaries).

Even as the exit from print not exactly the same, what matters - in my opinion - is that the count is correct. Another point is that a Counter allows other operations that may be useful (if you wish), such as knowing which are the most frequent models. But anyway, here are the solutions, see which is the most suitable for your case.

  • 1

    I was going to answer this with https://ideone.com/4UPv8i, very similar, but then the work called

  • 1

    Excellent solution @hkotsubo ! Both solve my problem and Counter gives me access to very interesting methods like most_common. I am a linguist and this Counter class will help me a lot. Thank you.

Browser other questions tagged

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