list index out of range when trying to resolve the issue of google Developer day 2010

Asked

Viewed 683 times

3

First of all, I am going to copy here the statement of the question to place:

In the quiet village of Ponteironuloville, all the phones have six digits. The phone company establishes the following rules on numbers:

  1. There can’t be two identical consecutive digits, because that’s boring;
  2. The sum of the digits has to be even, because that’s cool;
  3. The last digit can’t be the same as the first, because that’s bad luck.

So, given these perfectly reasonable, well designed and mature rules, how many phone numbers in the list below are valid? (The list of the question is at the beginning of my code.)

In view of the above, this is my attempt at a resolution:

lista = '''213752 216732 221063 221545 225583 229133 230648 233222 236043 237330
         239636 240138 242123 246224 249183 252936 254711 257200 257607 261424
         263814 266794 268649 273050 275001 277606 278997 283331 287104 287953
         289137 291591 292559 292946 295180 295566 297529 300400 304707 306931
         310638 313595 318449 319021 322082 323796 326266 326880 327249 329914
         334392 334575 336723 336734 338808 343269 346040 350113 353631 357154
         361633 361891 364889 365746 365749 366426 369156 369444 369689 372896
         374983 375223 379163 380712 385640 386777 388599 389450 390178 392943
         394742 395921 398644 398832 401149 402219 405364 408088 412901 417683
         422267 424767 426613 430474 433910 435054 440052 444630 447852 449116
         453865 457631 461750 462985 463328 466458 469601 473108 476773 477956
         481991 482422 486195 488359 489209 489388 491928 496569 496964 497901
         500877 502386 502715 507617 512526 512827 513796 518232 521455 524277
         528496 529345 531231 531766 535067 535183 536593 537360 539055 540582
         543708 547492 550779 551595 556493 558807 559102 562050 564962 569677
         570945 575447 579937 580112 580680 582458 583012 585395 586244 587393
         590483 593112 593894 594293 597525 598184 600455 600953 601523 605761
         608618 609198 610141 610536 612636 615233 618314 622752 626345 626632
         628889 629457 629643 633673 637656 641136 644176 644973 647617 652218
         657143 659902 662224 666265 668010 672480 672695 676868 677125 678315'''

lista = lista.split()
#como simplesmente copiei a lista, não quis separar 200 elementos manualmente.

validos = []
#lista vazia onde irei inserir os números válidos.

for ca in range(len(lista)):
    n_inv = False
    e = list(lista[ca])
    for cb in range(len(e) - 1):
        cc = cb + 1
        if e[cb] == e[cc]:
            n_inv = True
    if n_inv == False:
        validos.append(lista[ca])
#2 loops(externo e interno) para selecionar os números de acordo com a primeira 
#condição dada, até aqui tudo bem.


for ca in range(len(validos)):
    a = 0
    e = list(validos[ca]) #o IDLE acusa o erro aqui(list index out of range)
    for cb in range(len(e)):
        a += int(e[cb])
    if a % 2 != 0:
        del validos[ca]
#loop para filtrar os números anteriormente selecionados de acordo com a condição 2.

for ca in range(len(validos)):
    e = list(validos[ca])
    if e[0] == e[-1]:
        del validos[ca]
#loop para filtrar os números anteriormente selecionados de acordo com a condição 3.

print(len(validos))

I’ve been racking my brain for hours to make that code. I’ve had some other problems with it, but I managed to solve, mainly with the help of the python tutor. This I can’t visualize the execution because the site limits the loops by 300 to avoid endless loopings. If you can help me one more time, I really appreciate it.

3 answers

3


Look, I don’t know python, but I think in this part:

for ca in range(len(validos)):
    a = 0
    e = list(validos[ca]) #o IDLE acusa o erro aqui(list index out of range)
    for cb in range(len(e)):
        a += int(e[cb])
    if a % 2 != 0:
        del validos[ca]

You’re deleting the elements from the list at the same time you’re iterating it. As a result, during the iteration, the list decreases in size, but you still try to access all the elements as if they were still there. The result is that one hour you will end up trying to access an element outside the list.

I am thinking of the following solutions:

  • Redesign the loop to increase the ca only if the item has not been removed.
  • Instead of removing the elements from the list, replace them with something that indicates they should be disregarded (for example, a zero) and then at the end you count how many elements are not zeros.
  • Instead of removing the invalid elements from the list, copy the valid ones to another list that will then be used in the next step.
  • Iterate the list of numbers only once, already checking the three conditions in the same iteration. And then, just keep a count of how many valid numbers you found. With this, you don’t need to change or delete elements or insert them into auxiliary lists.
  • Strange, I thought that whenever I removed an element, when I returned to the beginning of the loop it would update the list size validos then I wouldn’t have this problem (since the condition of stop pro loop is the list size itself). I tried to modify with while, as you said, but the error persisted: ca = 0 while ca <= Len(validated): a = 0 e = list(validated[ca]) for cb in range(Len(e)): a += int(e[cb]) if a % 2 != 0: of the valid[ca] Else: ca += 1 '0' and remove them later.

  • 1

    @Jeffersoncarvalho I believe that because of performance, he will only evaluate the range(len(validos)) once. At least in all the other languages I know, that’s what happens. As for modifying the while, you used ca <= len(validos), but it should be ca < len(validos).

2

Like mentioned by Victor, the problem happens when you use the del to remove the item from the list. This happens in the last two loops for of the code:

for ca in range(len(validos))
    ...
    del validos[ca]

The expression len(validos) is evaluated only one time, at the moment range is evaluated. When you remove an element be by pop or del, the exception IndexError is generated.

As well quoted by Victor, instead of removing the invalid numbers, copy only the valid ones to the list validos.

Some lines of code could also be saved by evaluating conditions in the same loop for.

Your code with these modifications might look like this:

#!/usr/bin/python
# -*- coding: utf-8 -*-

lista = '''213752 216732 221063 221545 225583 229133 230648 233222 236043 237330
         239636 240138 242123 246224 249183 252936 254711 257200 257607 261424
         263814 266794 268649 273050 275001 277606 278997 283331 287104 287953
         289137 291591 292559 292946 295180 295566 297529 300400 304707 306931
         310638 313595 318449 319021 322082 323796 326266 326880 327249 329914
         334392 334575 336723 336734 338808 343269 346040 350113 353631 357154
         361633 361891 364889 365746 365749 366426 369156 369444 369689 372896
         374983 375223 379163 380712 385640 386777 388599 389450 390178 392943
         394742 395921 398644 398832 401149 402219 405364 408088 412901 417683
         422267 424767 426613 430474 433910 435054 440052 444630 447852 449116
         453865 457631 461750 462985 463328 466458 469601 473108 476773 477956
         481991 482422 486195 488359 489209 489388 491928 496569 496964 497901
         500877 502386 502715 507617 512526 512827 513796 518232 521455 524277
         528496 529345 531231 531766 535067 535183 536593 537360 539055 540582
         543708 547492 550779 551595 556493 558807 559102 562050 564962 569677
         570945 575447 579937 580112 580680 582458 583012 585395 586244 587393
         590483 593112 593894 594293 597525 598184 600455 600953 601523 605761
         608618 609198 610141 610536 612636 615233 618314 622752 626345 626632
         628889 629457 629643 633673 637656 641136 644176 644973 647617 652218
         657143 659902 662224 666265 668010 672480 672695 676868 677125 678315'''

lista = lista.split()
validos = []

for indice in range(len(lista)):
    soma = 0
    ff = 0
    invalido = True
    elemento = list(lista[indice])
    soma = sum(map(int, elemento))
    for caractere in range(len(elemento) -1):
        proximoCaractere = caractere + 1    
        if (elemento[caractere] == elemento[proximoCaractere]) or (int(soma) % 2 != 0) or (elemento[0] == elemento[-1]):
            invalido = True
            break
        else:
            invalido = False

    if invalido == False:       
        validos.append(elemento)    

print ("Válidos: {0} / Original: {1}".format(len(validos), len(lista)))

Functional example in repl it..

  • Interestingly, the code was actually much smaller. But the answer turned out wrong, its code generated 76 and the correct one would be 39. Maybe this happened because you forgot to add up the element numbers before checking if he was even.

  • 1

    @Jeffersoncarvalho Sorry I already corrected the code. =)

1

I found the question interesting and would like to complement with a solution with a face more OO.

# -*- coding: utf-8 -*-

from itertools import tee


class ListaTelefones(object):

    def __init__(self, lista_de_telefones):
        self.telefones = lista_de_telefones.split()
        self.telefones_validos = []
        self.telefones_invalidos = []

    def dois_a_dois(self, iterable):
        "s -> (s0,s1), (s1,s2), (s2, s3), ..."
        a, b = tee(iterable)
        next(b, None)
        return zip(a, b)

    def digitos_consecutivos_identicos(self, telefone):
        """ Não pode haver dois dígitos consecutivos idênticos,
            porque isso é chato. """
        return all([True if el1 != el2 else False
                   for el1, el2 in self.dois_a_dois(telefone)])

    def soma_digitos_e_par(self, telefone):
        """ A soma dos dígitos tem que ser par, porque isso é legal. """
        return sum(map(int, telefone)) % 2 == 0

    def primeiro_e_ultimo_digito_diferentes(self, telefone):
        """ O último dígito não pode ser igual ao primeiro,
            porque isso dá azar. """
        return telefone[0] != telefone[-1]

    def checar_validade(self, telefone):
        condicao1 = self.digitos_consecutivos_identicos(telefone)
        condicao2 = self.soma_digitos_e_par(telefone)
        condicao3 = self.primeiro_e_ultimo_digito_diferentes(telefone)
        return all([condicao1, condicao2, condicao3, ])

    def obter_telefones_validos(self):
        self.telefones_validos = []
        for li in self.telefones:
            if self.checar_validade(li):
                self.telefones_validos.append(li)

    def imprimir_telefones(self):
        for li in self.telefones:
            print(li)

    def imprimir_telefones_validos(self):
        for li in self.telefones_validos:
            print(li)

    def contar_telefones(self):
        print(len(self.telefones))

    def contar_telefones_validos(self):
        print(len(self.telefones_validos))


lista = '''213752 216732 221063 221545 225583 229133 230648 233222 236043 237330
         239636 240138 242123 246224 249183 252936 254711 257200 257607 261424
         263814 266794 268649 273050 275001 277606 278997 283331 287104 287953
         289137 291591 292559 292946 295180 295566 297529 300400 304707 306931
         310638 313595 318449 319021 322082 323796 326266 326880 327249 329914
         334392 334575 336723 336734 338808 343269 346040 350113 353631 357154
         361633 361891 364889 365746 365749 366426 369156 369444 369689 372896
         374983 375223 379163 380712 385640 386777 388599 389450 390178 392943
         394742 395921 398644 398832 401149 402219 405364 408088 412901 417683
         422267 424767 426613 430474 433910 435054 440052 444630 447852 449116
         453865 457631 461750 462985 463328 466458 469601 473108 476773 477956
         481991 482422 486195 488359 489209 489388 491928 496569 496964 497901
         500877 502386 502715 507617 512526 512827 513796 518232 521455 524277
         528496 529345 531231 531766 535067 535183 536593 537360 539055 540582
         543708 547492 550779 551595 556493 558807 559102 562050 564962 569677
         570945 575447 579937 580112 580680 582458 583012 585395 586244 587393
         590483 593112 593894 594293 597525 598184 600455 600953 601523 605761
         608618 609198 610141 610536 612636 615233 618314 622752 626345 626632
         628889 629457 629643 633673 637656 641136 644176 644973 647617 652218
         657143 659902 662224 666265 668010 672480 672695 676868 677125 678315'''


lista_telefones = ListaTelefones(lista_de_telefones=lista)
lista_telefones.obter_telefones_validos()
lista_telefones.imprimir_telefones_validos()
lista_telefones.contar_telefones_validos()

https://gist.github.com/arthuralvim/f0e7f62414e4ade71745

  • Much of this code I still don’t understand because I’m beginner, rs But at least the final answer is correct, which is 39.

Browser other questions tagged

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