Why is my code "swallowing" string on a list?

Asked

Viewed 75 times

0

letras = ["A", "B", "C", "B"]
vogais = ["a", "e", "i", "o", "u"]

for letra in letras:
    if letra.lower() in vogais:
        print(letra.upper())
        letras.remove(letra)
    elif letra.lower() not in vogais:
        print(letra)

Because my code isn’t reading the first "B" that’s on the list of letters?

  • Must have the same value in the two "B" see there.

3 answers

1

As explained here, here and here, remove elements from a list in it loop that iterates on it can cause these problems. To illustrate better, let’s modify a little the loop:

letras = ["A", "B", "C", "B"]
for indice, letra in enumerate(letras):
    print(f' antes: {indice}={letra} - lista={letras}')
    letras.remove(letra)
    print(f'depois: {indice}={letra} - lista={letras}')

I use enumerate to iterate through the indexes and their elements at the same time. The output is:

 antes: 0=A - lista=['A', 'B', 'C', 'B']
depois: 0=A - lista=['B', 'C', 'B']
 antes: 1=C - lista=['B', 'C', 'B']
depois: 1=C - lista=['B', 'B']

That is, in the first iteration (when the index is 0), the letra corresponds to the first element (index zero), which is the letter "A". After removing it, the list becomes ['B', 'C', 'B'].

In the second iteration (when the index is 1), letra corresponds to the second element of the list. But since the list has been modified and "A" has been removed, the second element (which is at index 1) is the letter "C". Therefore the first "B" is skipped.


To documentation gives you some alternatives to avoid this problem and do what you want. Or you create another list with the elements you want (that is, everything that is not a vowel):

letras = ["A", "B", "C", "B"]
vogais = ["a", "e", "i", "o", "u"]
resultado = []
for letra in letras:
    if letra.lower() in vogais:
        print(letra.upper())
    else:
        print(letra)
        resultado.append(letra)

print(resultado)

Or you iterate over a copy of the list:

letras = ["A", "B", "C", "B"]
vogais = ["a", "e", "i", "o", "u"]
for letra in letras.copy(): # itero sobre uma cópia
    if letra.lower() in vogais:
        print(letra.upper())
        letras.remove(letra) # agora posso remover, pois não afeta a cópia
    else:
        print(letra)

Also note that you don’t need elif. In the if you see if the letter is in the vowel list. If so, enter if, and whether it arrived at the else, it is because it is not, so it is redundant and unnecessary to test it again.

0

How about using the exclusion by index?

letras = ["A", "B", "C", "E", "B"]
vogais = ["a", "e", "i", "o", "u"]
i = 0
while i < len(letras):
    if letras[i].lower() in vogais:
        del letras[i]
        # os próximos elementos terão índice reduzido em 1, não devendo-se inclementar i
    else:
        i+=1
print(letras)

0

This is happening because at the time you’re giving letters.remove(letter) in its code the size of the list is being changed and consequently the index of all items in it is decreasing by 1.

For example:

  • the item "To" of letters has a Index 0 before removal and the first letter "B" has the Index 1.

["A", "B", "C", "B"] # respectively are: 0, 1, 2, 3

  • So the lyrics "To" is removed the Index of "B" becomes 0 and as the loop has already passed through it the first "B" is not read because your list got like this:

["B","C","B"] # respectively are: 0, 1, 2 By now the for has passed the Index 0 and will move on to the next until you reach the Index 2

Below is a simple solution without changing your code too much:

    1. Adding a list of letters to be removed and append to it as well.

In the case: removed = [ ] and removed.append(letter)

letras = ["A", "B", "C", "B"] 
vogais = ["a", "e", "i", "o", "u"]

removidos = []

for letra in letras: 
    if letra.lower() in vogais:
        print(f'A letra "{letra}" será removida')
        removidos.append(letra) # Adicionando a letra na lista de remoção futura para não atrapalhar a leitura da lista atual

    elif letra.lower() not in vogais: # Você simplesmente pode usar um else aqui no lugar do elif caso não exista mais outra condição
        print(letra)
    1. Removing the letter without disturbing the reading of the original list:

Using a loop for to read all items within the removed list and the letters.remove(letra_removed) to remove them from the original list

for letra_removida in removidos:
    letras.remove(letra_removida) # Utilizando a lista de removidos para tirar as vogais depois do outro loop

3.1 Way to view the whole list:

print(f"Lista sem vogais: {letras}") # Resultado

Your outworking will be:

  • Vowel-less list: ["B","C","B"]

3.2 Or one item at a time:

for letra in letras:
    print(letra)

Here yours outworking will be:

  • B
  • C
  • B

I hope I’ve helped!

Browser other questions tagged

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