Contrary to what some responses have stated, you should not remove items from the list within it loop that iterates on it. It may even work in some cases, but in others it won’t, as we can see below.
Consider the case below, which removes elements that are empty strings:
lista = [ '', '', '', 'x' ]
for x in lista:
if x == '': # se for string vazia, remove
lista.remove(x)
# deveria sobrar só o 'x', mas...
print(lista) # ['', 'x']
This code prints out:
['', 'x']
One of the elements that should be removed was not.
Why does this happen?
To better understand what happened, let’s use another list:
lista = [ '1', '2', '3', 'x' ]
for x in lista:
if x.isdigit(): # se for um dígito, remove
lista.remove(x)
print(lista) # ['2', 'x']
Now I’m using isdigit()
to remove strings that contain only digits. However, the result is the list ['2', 'x']
.
This is because in the first iteration of for
, it takes the first element from the list (the string '1'
). Like isdigit()
returns True
for this string, it enters the if
and the '1'
is removed from the list.
In the second iteration of for
, it takes the second element from the list. But as the '1'
has already been removed, the second element is now the string '3'
(that is, the string '2'
, that should have been removed, was skipped). That’s why the '2'
still appears in the final result.
In more detail:
- first iteration of
for
, the list goes like this:
[ '1', '2', '3', 'x' ]
- the first item in the list is checked (
'1'
), and how isdigit()
returns True
, this is removed. IE, now the list is like this:
[ '2', '3', 'x' ]
- in the second iteration of
for
, he takes the second element, which is the '3'
, and isdigit()
also returns True
, then this one is removed. Now the list is like this:
[ '2', 'x' ]
- in the third iteration of
for
, he tries to catch the third element, but as the list only has 2 elements, the loop closes.
You can make sure that this happens by putting a print
in the for
:
lista = [ '1', '2', '3', 'x' ]
for x in lista:
print('testando', x)
if x.isdigit():
print('removendo', x)
lista.remove(x)
The exit is:
testando 1
removendo 1
testando 3
removendo 3
As you can see, the '2'
was "jumped". And the 'x'
not even checked (if it was also a string that contains only digits, that is, something that should be removed, it also would not be removed).
So how do I do?
If you want to delete some elements from the list by following certain criteria, you can create another list containing only the elements you need. Ex:
lista = [ '', '', '', 'x' ]
# manter apenas os elementos que não forem vazios
lista = [ x for x in lista if x != '' ]
print(lista) # ['x']
I used the syntax of comprehensilist on, to get the elements that are not empty strings. In this case, I assigned them to the same list, but you could create another one if you wanted:
lista = [ '', '', '', 'x' ]
# manter apenas os elementos que não forem vazios
outra_lista = [ x for x in lista if x != '' ]
Thus there is no problem cited at the beginning, of improperly skipping some elements.
Another alternative is to use the module itertools
, and its function filterfalse
:
from itertools import filterfalse
lista = [ '', '', '', 'x' ]
lista = list(filterfalse(lambda s: s == '', lista))
print(lista) # ['x']
filterfalse
considers the elements for which the condition is false. In this case, I used as a condition a lambda that checks if the string is empty, then it will return the elements that are not empty.
About the other doubts:
how do I go through the list and check if any data has been entered blank and treat it to fill in again?
In this case you could do something like this:
lista = [ '', '', '', 'x' ]
for i, _ in enumerate(lista):
while lista[i] == '':
lista[i] = input('digite um número:')
The while
serves to ask the user to type something, and while this something is the empty string, it asks you to type again. If the item is not empty, it does not enter the while
and item is not modified.
I wanted to do it in a way that wasn’t treated by if
's in the input
or while
. Could it be? Or is there a Python function that calls in input
not to enter empty data?
Why don’t you want to use if
or while
? They’re two of the most basic programming structures, and it’s okay to use them.
In the case of input
, just make a loop asking to enter the information, until it is what you want:
while True:
s = input('digite o número: ')
if s != '':
break
If the string s
is empty, it continues on while
, asking you to type again. If it is not empty, enter if
and the break
interrupts the loop.
Although in your case you are asking you to enter a number, so why not just validate if it is an even number?
while True:
try:
n = int(input('digite o número: '))
break
except ValueError:
print('Não foi digitado um número')
If no number is entered, int()
will launch a ValueError
and fall into the block except
(which in turn informs that no number has been entered), and the while
continues, asking the user to type again. If the conversion to number is correct, the code falls on break
, interrupting the loop.
In the case, int()
only accepts whole numbers. But if you want numbers with decimals, just switch to float()
.
So you guarantee right at the beginning that your list will only have valid values, and you don’t even need to treat them afterwards.
One more thing: if you want to add values at the end of the list, use append
instead of insert
. Just do lista.append(valor)
, that the value is inserted at the end of the list (see more details in documentation).
Another detail is that lista.insert
returns None
, then it makes no sense to assign the return of insert
in a variable, as you did in variavel_1
and variavel_2
.
On "blank data"
It is not very clear what you consider a "blank die". If it is only a space, then it is okay to use what one of the answers suggested (compare to ' '
- note that there is a space between the quotes). In my examples I used an empty string (''
), which is what input
returns when only one is typed ENTER. Both are valid, depending on what you need.
But what if multiple spaces are typed (e.g.: ' '
), do you also consider it to be "blank data"? If so, a way to compare would be:
# s é a string que estou verificando se é "em branco"
if s.isspace() or s == '':
# em branco (ou vazio)
I used the method isspace()
that checks if the string only has spaces - remembering that the definition of "space" that it uses is "a character that has the Unicode category Zs ("Separator, space"), or the two-way class is WS, B or S." (see here the complete list of these characters).
But isspace()
requires there to be at least one character in the string, so I also test if the string is empty. Another way to do this is to eliminate the spaces at the beginning and end of the string (using strip()
) and check that what is left is empty:
if s.strip() == '':
# s é "em branco"
That part here: "do in a way that is not treated by ifs in the input" means what? That the verification should be done only after the whole completed list?
– Augusto Vasques
I don’t know if it would be right.. But I didn’t want to deal with ifs in input.
– imaestri
Do the checks right in the lobby as @Filipemachado suggested.
– Augusto Vasques
All right! Thanks..
– imaestri