Percursos
/
Python
Python
/
Exercícios
/
A montanha-russa colossal da Chaitana
A montanha-russa colossal da Chaitana

A montanha-russa colossal da Chaitana

Exercício de aprendizagem

Introdução

Uma list é uma coleção mutável de itens em sequência. Tal como a maioria das coleções (vê os tipos incorporados tuple, dict e set), as lists podem conter referências a qualquer tipo de dados (ou a vários) - incluindo outras lists. As lists podem ser copiadas no todo ou em parte através da notação de fatiamento ou com recurso a <list>.copy(). Tal como qualquer sequência, os elementos dentro das lists são referenciados por um número 0-based index a partir da esquerda, ou por um número -1-based index a partir da direita.

As lists suportam tanto operações de sequência comuns como mutáveis, tais como min(<list>)/max(<list>), <list>.index(), <list>.append() e <list>.reverse(). Os elementos dentro de uma list podem ser iterados com a construção for item in <list>. Podes usar for index, item in enumerate(<list>) quando precisares tanto do índice como do valor do elemento.

O Python também disponibiliza muitos métodos de list úteis para trabalhar com lists. Abaixo apresentamos uma seleção desses list methods.

Tem em atenção que, quando manipulas uma list com um list-method, alteras o objeto list que foi passado. Se não quiseres alterar a list original, tens de fazer pelo menos uma shallow copy dela, através de fatiamento ou de <list>.copy().

Adicionar itens

Para adicionar um item ao fim, ou ao "lado direito", de uma list existente, usa <list>.append(<item>):

>>> numbers = [1, 2, 3]
>>> numbers.append(9)

>>> numbers
[1, 2, 3, 9]

Em vez de fazer append, <list>.insert() dá-te a possibilidade de adicionar o item a um índice específico da list. Aceita 2 parâmetros:

  1. o <index> onde queres que o item seja inserido.
  2. o <item> a inserir.

Nota: se o index indicado for 0, o item é adicionado ao início ("lado esquerdo") da list. Se o index indicado for maior do que o último index da list, o item é adicionado na posição final, o equivalente a usar <list>.append(<item>).

>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)

>>> numbers
[-2, 1, 2, 3]

>>> numbers.insert(1, 0)

>>> numbers
[-2, 0, 1, 2, 3]

Podes usar <list>.extend(<item>) para combinar uma list existente com os elementos de outro iterável (por exemplo, um set, tuple, str ou list). O iterável é desempacotado e os elementos são acrescentados por ordem (usar <list>.append(<item>) nesta situação adicionaria o iterável inteiro como um único item.).

>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]

>>> numbers.extend(other_numbers)

>>> numbers
[1, 2, 3, 5, 6, 7]

>>> numbers.extend([8, 9])

>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]

>>> numbers.append([8,9])

>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9, [8, 9]]

Remover itens

Para eliminar um item de uma list, usa <list>.remove(<item>), passando como argumento o item a remover. <list>.remove(<item>) lança um ValueError se o item não estiver presente na list.

>>> numbers = [1, 2, 3]
>>> numbers.remove(2)

>>> numbers
[1, 3]

# Trying to remove a value that is not in the list throws a ValueError
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list

Em alternativa, usar o método <list>.pop(<index>) remove e faz return de um elemento, para o poderes usar.

<list>.pop(<index>) aceita um parâmetro opcional: o index do item a remover e a devolver. Se o argumento index (opcional) não for indicado, o elemento final da list é removido e devolvido. Se o index indicado for superior ao index do último item, é lançado um IndexError.

>>> numbers = [1, 2, 3]

>>> numbers.pop(0)
1

>>> numbers
[2, 3]

>>> numbers.pop()
3

>>> numbers
[2]

>>> numbers.pop(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: pop index out of range

Todos os elementos podem ser removidos de uma list com list.clear(). Não aceita parâmetros.

>>> numbers = [1, 2, 3]
>>> numbers.clear()

>>> numbers
[]

Inverter e reordenar

O método <list>.reverse() inverte a ordem dos elementos no próprio local.

>>> numbers = [1, 2, 3]
>>> numbers.reverse()

>>> numbers
[3, 2, 1]

Uma list pode ser reordenada no próprio local com a ajuda de <list>.sort(). A ordem de ordenação predefinida é crescente a partir da esquerda. A documentação do Python apresenta dicas e técnicas adicionais de ordenação.

Note

De 2002 a 2022, o Python usava internamente um algoritmo chamado Timsort para organizar as lists, mas passou a usar o Powersort a partir do Python 3.11.

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]

# The default sort order is *ascending*.
>>> names.sort()

>>> names
["Bruce", "Natasha", "Thor", "Tony"]

Se quiseres uma ordem decrescente, passa o argumento reverse=True:

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)

>>> names
["Tony", "Thor", "Natasha", "Bruce"]

Nos casos em que não queres alterar a list original, podes usar a função incorporada sorted(<iterable>) para devolver uma cópia ordenada.

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]

>>> sorted(names)
['Bruce', 'Natasha', 'Thor', 'Tony']

Ocorrências de um item numa list

O número de ocorrências de um elemento numa list pode ser calculado com a ajuda de list.count(<item>). Aceita como argumento o item a contar e devolve o número total de vezes que esse elemento aparece na list.

>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]

>>> items.count(1)
3

Encontrar o índice de itens

<list>.index(<item>) devolve o número index da primeira ocorrência de um item passado. Se não houver ocorrências, é lançado um ValueError. Se não precisares da posição exata de um item, o operador in incorporado é mais eficiente para verificar se uma list contém um determinado valor.

A indexação tem base zero a partir da esquerda, por isso a posição do item "primeiro" é 0. A indexação também funciona a partir da direita, começando em -1.

>>> items = [7, 4, 1, 0, 2, 5]

>>> items.index(4)
1

>>> items.index(10)
ValueError: 10 is not in list

Também podes indicar os índices start e end para restringir a pesquisa a uma secção específica da list:

>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]

>>> names.index("Tina")
0

>>> names.index("Tina", 2, 5)
3

Instruções

A Chaitana é proprietária de um parque de diversões muito popular. Só tem uma atração, mesmo no centro de terrenos belissimamente ajardinados: The Biggest Roller Coaster in the World(TM). Apesar de só existir esta atração, há pessoas que viajam de todo o mundo e ficam horas na fila para poderem andar na montanha-russa da Chaitana.

Há duas filas para esta atração, cada uma representada por uma list:

  1. Fila normal
  2. Fila express (também conhecida como Fast-track), onde as pessoas pagam a mais para ter acesso prioritário.

Foi-te pedido que escrevas algum código para gerir melhor os visitantes do parque. Tens de implementar as seguintes funções o mais depressa possível, antes que os visitantes (e a tua chefe, a Chaitana!) fiquem irritados. Certifica-te de que lês com atenção. Algumas tarefas pedem que alteres ou atualizes a fila existente, enquanto outras pedem que faças uma cópia dela.

1. Acrescenta-me à fila

Define a função add_me_to_the_queue() que recebe 4 parâmetros <express_queue>, <normal_queue>, <ticket_type>, <person_name> e devolve a fila adequada atualizada com o nome da pessoa.

  1. <ticket_type> é um int, em que 1 == express_queue e 0 == normal_queue.
  2. <person_name> é o nome (como str) da pessoa a acrescentar à fila respetiva.
>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=1, person_name="RichieRich")
...
["Tony", "Bruce", "RichieRich"]

>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=0, person_name="HawkEye")
....
["RobotGuy", "WW", "HawkEye"]

2. Onde estão os meus amigos?

Uma pessoa chegou atrasada ao parque, mas quer juntar-se à fila onde os amigos estão à espera. Mas não faz ideia de onde os amigos estão na fila e não há cobertura de telemóvel para lhes telefonar.

Define a função find_my_friend() que recebe 2 parâmetros queue e friend_name e devolve a posição na fila do nome da pessoa.

  1. <queue> é a list das pessoas que estão na fila.
  2. <friend_name> é o nome do amigo cujo índice (lugar na fila) precisas de encontrar.

Lembra-te: a indexação começa em 0 a partir da esquerda e em -1 a partir da direita.

>>> find_my_friend(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], friend_name="Steve")
...
1

3. Posso juntar-me a eles?

Agora que os amigos já foram encontrados (na tarefa n.º 2 acima), quem chegou atrasado gostaria de se juntar a eles no lugar deles na fila. Define a função add_me_with_my_friends() que recebe 3 parâmetros queue, index e person_name.

  1. <queue> é a list das pessoas que estão na fila.
  2. <index> é a posição onde a nova pessoa deve ser acrescentada.
  3. <person_name> é o nome da pessoa a acrescentar na posição do índice.

Devolve a fila atualizada com o nome de quem chegou atrasado.

>>> add_me_with_my_friends(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], index=1, person_name="Bucky")
...
["Natasha", "Bucky", "Steve", "T'challa", "Wanda", "Rocket"]

4. Pessoa mal-educada na fila

Acabaste de ouvir na fila que há uma pessoa mesmo má a empurrar, a gritar e a criar confusão. Tens de expulsar esse malfeitor por mau comportamento!

Define a função remove_the_mean_person() que recebe 2 parâmetros queue e person_name.

  1. <queue> é a list das pessoas que estão na fila.
  2. <person_name> é o nome da pessoa que precisa de ser expulsa.

Devolve a fila atualizada sem o nome da pessoa má.

>>> remove_the_mean_person(queue=["Natasha", "Steve", "Eltran", "Wanda", "Rocket"], person_name="Eltran")
...
["Natasha", "Steve", "Wanda", "Rocket"]

5. Homónimos

Pode ser que nunca tenhas visto duas pessoas sem qualquer parentesco que sejam exatamente iguais, mas já viste de certeza pessoas sem qualquer parentesco com exatamente o mesmo nome (homónimos)! Hoje, parece que há muitos deles entre os presentes. Queres saber quantas vezes um determinado nome aparece na fila.

Define a função how_many_namefellows() que recebe 2 parâmetros queue e person_name.

  1. <queue> é a list das pessoas que estão na fila.
  2. <person_name> é o nome que achas que pode aparecer mais do que uma vez na fila.

Devolve o número de ocorrências de person_name, como um int.

>>> how_many_namefellows(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"], person_name="Natasha")
...
2

6. Remove a última pessoa

Infelizmente, hoje o parque está superlotado e tens de remover a última pessoa da fila normal (vais dar-lhe um vale para voltar na Fast-track noutro dia). Vais ter de definir a função remove_the_last_person() que recebe 1 parâmetro, queue, que é a lista das pessoas que estão na fila.

Deves atualizar a list e também fazer return do nome da pessoa que foi removida, para lhe poderes escrever um vale.

>>> remove_the_last_person(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"])
...
'Rocket'

7. Ordena a lista da fila

Por motivos administrativos, precisas de obter todos os nomes de uma determinada fila por ordem alfabética.

Define a função sorted_names() que recebe 1 argumento, queue (a list das pessoas que estão na fila), e devolve uma cópia sorted da list.

>>> sorted_names(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"])
...
['Eltran', 'Natasha', 'Natasha', 'Rocket', 'Steve']
Editar via GitHub A ligação abre numa nova janela ou separador
Python Exercism

Estás pronto para começar A montanha-russa colossal da Chaitana?

Inscreve-te no Exercism para aprenderes e dominares Python com 17 conceitos146 exercícios, e mentoria humana real, tudo grátis.