List Comprehension returning zero

Asked

Viewed 73 times

-1

Guys, I need your help. I have a code in python that I would like to return the amount of values that meet a criterion, but it is returning zero. The txt file contains data like this:

567886786765211267878783647866575678666869837678681226786789 cancelado

562342342342343123124234534645656756756756756756756765756178 assinado

555456456546544324234235434534645645645645654645645645645631 assinado

520757345873458374657834857897989988786785645342111575756432 cancelado

554234534534645647567867987089078655345231342536456575676777 cancelado

That’s the return I’m getting:

{'P1': {'Total': 2, 'Ativos': 0}, 'P2': {'Total': 2, 'Ativos': 0}, 'P3': {'Total': 1, 'Ativos': 0}}

And I’d like him to return to me like this:

{'P1': {'Total': 2, 'Ativos': 0}, 'P2': {'Total': 2, 'Ativos': 1}, 'P3': {'Total': 1, 'Ativos': 1}}

That is the code

with open('log.txt','r') as file:
    arquivo = filter(None, [line.rstrip('\n').split() for line in file])

prefixo = []
    status = []
    for linha in arquivo:
        prefixo.append(linha[0][:2])
        status.append(linha[1])
    data = zip(prefixo, status)
    
paises = {
    'P1': {
        'Total': [p for p in prefixo if p == '55'].count('55'),
        'Ativos': [d for d in data if d[0] == '55' and d[1] == 'assinado'].count('assinado')
    },
    'P2': {
        'Total': [p for p in prefixo if p == '56'].count('56'),
        'Ativos': [d for d in data if d[0] == '56' and d[1] == 'assinado'].count('assinado')
    },

    'P3': {
        'Total': [p for p in prefixo if p == '52'].count('52'),
        'Ativos': [d for d in data if d[0] == '52' and d[1] == 'assinado'].count('assinado')
    },
}

If you can help me

  • 1

    Without seeing the file (I’m assuming you have, because of the for linha in arquivo), we can only guess: put [ d[1] for d in data etc... (instead of just d for d in data). Anyway, could [Edit] and put some lines of the file as example?

  • @hkotsubo I was trying to edit the post and was not getting it. I will edit but I cannot share the file.

  • @hkotsubo I made the change you mentioned, but continues with the same result

  • It doesn’t have to be the whole file, it could just be a piece that reproduces the problem, otherwise we can’t even test, let alone know what’s wrong... Or, change the data to something that can be disclosed, as long as the main problem remains (count to zero). Otherwise we will stay in this divination ("try it", "did not give"), and as you realized, it is not productive

  • hkotsubo take a look and see if you can understand

1 answer

1


The problem is that zip returns an iterable which can only be traversed/iterated once. Example:

x = [1, 2, 3]
y = [ 'a', 'b', 'c']
z = zip(x, y)

print('primeira vez:', [ d for d in z ])
print('segunda vez:', [ d for d in z ])

The output of this code is:

primeira vez: [(1, 'a'), (2, 'b'), (3, 'c')]
segunda vez: []

For the first time I go through all the elements of the eternal, and the second time has nothing to go through. That is why your counts result in zero, because from the second time you travel the data, has no other element, so the count is zero.

One way - not very efficient - to solve would be to put the content in a list:

data = list(zip(prefixo, status))

And in the list comprehensions you have to take the element that corresponds to the status (ie: [d[1] for d in data if d[0] == '55' and d[1] == 'assinado'].count('assinado')).

But this solution is inefficient because then you go through the same list several times, and it calls count several times (with each call from count go through the list again). Not to mention that you are putting all the contents of the file in a list (if it is too large, it will be an unnecessary waste of memory).

A better solution is to read the file line by line and update the dictionary with each line read. An example of how it would look:

def get_pais(prefixo): # não precisa do slice [:2], basta ver se começa com os dígitos
    if prefixo.startswith('55'):
        return 'P1'
    elif prefixo.startswith('56'):
        return 'P2'
    elif prefixo.startswith('52'):
        return 'P3'
    return None

paises = {}
with open('log.txt', 'r') as arquivo:
    for linha in arquivo: # lê o arquivo linha a linha
        dados = linha.rstrip('\n').split()
        if len(dados) != 2: # se a linha não tem todos os dados, vai para a próxima
            continue
        prefixo, status = dados # separa o prefixo e o status
        pais = get_pais(prefixo)

        if pais is not None: # se o país é válido
            if pais not in paises:  # se o país ainda não está no dicionário paises
                paises[pais] = { 'Total': 0, 'Ativos': 0 }
            paises[pais]['Total'] += 1
            if status == 'assinado':
                paises[pais]['Ativos'] += 1
  • Valueerror: not enough values to unpack (expected 2, got 0)

  • @Eduardolopes There should be blank line in the file. That’s why we ask to put a piece of it, instead of just one line...

  • hkotsubo there is this possibility of there being blank spaces between one line and another. With this file code = filter(None, [line.rstrip(' n').split() for line in file]) it is possible to remove these spaces

  • @Eduardolopes You don’t need this. I updated the answer

  • hkotsubo doesn’t really need a filter. I realized that the memory expense for each new insertion of information in the file, would be really expensive.

  • Thank you @hkotsubo, clarified a lot. How can I keep in touch with you?

  • @Eduardolopes If the answer solved your problem, you can accept it, see here how and why to do it. It is not mandatory, but it is a good practice of the site, to indicate to future visitors that it solved the problem. About contact, just continue participating in the site I’m always here

Show 2 more comments

Browser other questions tagged

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