Baixe o app para aproveitar ainda mais
Prévia do material em texto
Universidade Federal de Ouro Preto Instituto de Ciências Exatas e Biológicas Departamento de Computação BCC701 Programação de Computadores I Semestre: 2021-01 Aula Prática – Estrutura Homogênea: VETOR (1) Pré-requisitos: • Estar familiarizado com o conteúdo das aulas anteriores e ter realizado as tarefas correspondentes. • Ler as seções 7.1, 7.3.1, 7.3.3 e 7.3.6 do livro texto da disciplina. • Assistir os v́ıdeos e/ou aulas teóricas correspondentes. Resumo: • Aprendemos, até aqui, que uma variável tem a capacidade de armazenar um único valor na memória, por exemplo: fruta = ‘maç~a’ e quantidade = 5. • Porém, muitas vezes temos a necessidade de manipular diversos valores que estão relacionados a alguma caracteŕıstica. Suponha que você precise manipular o nome e a quantidade de várias frutas. Seriam necessárias várias variáveis para armazenar cada valor. • A solução ideal para isso é através de vetores. Que é uma estrutura de dados capaz de armazenar vários valores em uma única variável. • A principal caracteŕıstica dos vetores é que eles são ditos homogêneos, o que significa que todos os valores armazenados em um vetor devem ser de um mesmo tipo. Para manipular os nomes e as quantidades de frutas, podeŕıamos usar duas variáveis: frutas = [ ‘maç~a’, ‘laranja’, ‘abacaxi’ ] e quantidades = [ 5, 3, 1 ], por exemplo. Neste caso, o número e a ordem dos elementos pode determinar a relação entre o nome e a quantidade de cada fruta. • Para manipular e acessar os valores de forma individual, precisamos utilizar algo que represente única e exclusivamente um dos elementos do vetor. Isto é feito a partir de sua posição (ou ı́ndice), que é determinado por um contador de valor inteiro que se inicia por 0 (zero). Por exemplo: frutas[0] armazena o valor ‘maç~a’, frutas[1] armazena o valor ‘laranja’, e assim por diante. • Neste nosso exemplo, os nomes das frutas e as suas quantidades podem ser associadas pelo ı́ndice, ou seja, a terceira fruta se chama frutas[2] (valor ‘laranja’), e a sua quantidade é quantidades[2] (valor 1). • Algumas operações com vetores que devem ser bem assimiladas: 1 # Criando vetor por atribuição: 2 vetor = [ ] # vetor vazio, não tem nenhum elemento 3 vetor = [ 10, 20, 30, 40 ] # vetor com 4 elementos 4 # Adicionando elementos: 5 vetor.append(100) # novo conteúdo: [ 10, 20, 30, 40, 100 ] 6 vetor.append(300) # novo conteúdo: [ 10, 20, 30, 40, 100, 300 ] 7 # Removendo elementos: 8 vetor.pop(0) # novo conteúdo: [ 20, 30, 40, 100, 300 ] 9 vetor.pop(2) # novo conteúdo: [ 20, 30, 100, 300 ] 10 # Alterando elementos: 11 vetor[1] = 35 # novo conteúdo: [ 20, 35, 100, 300 ] 12 vetor[3] = vetor[3] + 10 # novo conteúdo: [ 20, 35, 100, 310 ] 13 # Quantidade de elementos 14 qtd = len(vetor) # variável qtd assume o valor 4 1 • É muito importante compreender bem a diferença entre os valores armazenados no vetor e os ı́ndices que representam as suas posições de armazenamento. Normalmente é necessário processar os valores do vetor determinando um padrão de acesso aos seus ı́ndices. É muito comum fazer isso através de um laço, onde o contador é responsável por determinar os ı́ndices e o bloco de comandos processa os valores para cumprir alguma tarefa. No código a seguir nós fazemos o somatório de todos os elementos do vetor definido anteriormente: 1 soma = 0 2 for i in range(qtd): 3 soma += vetor[i] 4 print(soma) Neste outro código, processamos o somatório dos valores armazenados em ı́ndices pares: 1 soma = 0 2 for i in range(0, qtd, 2): 3 soma += vetor[i] 4 print(soma) E neste outro código, processamos o somatório dos valores armazenados em ı́ndices ı́mpares: 1 soma = 0 2 for i in range(1, qtd, 2): 3 soma += vetor[i] 4 print(soma) Observe que nossa estratégia é usar a sintaxe do range para determinar o padrão de acesso aos ı́ndices, e para fazer o somatório precisamos usar o valor armazenado no vetor, acessando o ı́ndice determinado pelo contador. • Nas Seções 7.3.1 e 7.3.3 do livro texto da disciplina nós criamos funções úteis sobre a manipulação de vetores, é muito importante que você compreenda bem o que elas fazem e como utilizá-las. É recomendável também que você entenda como elas realizam suas tarefas. Um resumo das funções: – criarVetor(qtdElementos, valorPadrao): cria e retorna um novo vetor contendo qtdElementos, todos armazenando o mesmo valor, definido por valorPadrao. – preencherVetor(valores, conversao): cria e retorna um novo vetor contendo os valores definidos na string valores, convertidos para o tipo definido por conversao. A string valores segue um padrão, ela define todos os valores do vetor separados por v́ırgula, por exemplo: ‘10, 20, 30, 40’ gera o vetor [10, 20, 30, 40] como resultado da função. • Na Seção 7.3.6, aprendemos a criar e usar uma biblioteca de funções. Crie um arquivo chamado biblio- teca.py, contendo as funções listadas anteriormente, com o código apresentado nas Seções 7.3.1 e 7.3.3, para que possa utilizar as funções nesta atividade prática fazendo a importação: 1 from biblioteca import * • Nesta prática a intenção é reforçar seus conhecimentos em todos estes recursos e praticar sua utilização na construção de programas que resolvam algum problema espećıfico. Se você não está familiarizado com os itens listados acima, consulte os pré-requisitos da prática, listados anteriormente. 2 Tarefa 1: Criando vetores com valores definidos pelo usuário A maioria dos exerćıcios envolvendo vetor começará com a definição dos valores a serem armazenados em um ou mais vetores. Basicamente, temos duas estratégias para fazer isso. A primeira através da definição de entradas individuais, e a segunda a partir de uma única entrada e a chamada da função preencherVetor. No programa a seguir, preenchemos o vetor conhecendo a quantidade de elementos: 1 qtd = int(input(’Quantidade de elementos: ’)) 2 vetor = [] 3 for i in range(qtd): 4 valor = int(input(f’Valor {i+1}: ’)) 5 vetor.append(valor) 6 print(f’Vetor definido: {vetor}’) Observe que, uma vez conhecendo o tamanho do vetor, podemos usar um laço for para ler e adicionar cada valor a ser armazenado no vetor. Antes deste laço temos que criar um vetor vazio. Observe que quando colocarmos o vetor no print, os valores serão impressos seguindo o padrão [10, 20, 30, 40], com os valores dentro de colchetes e separados por v́ırgula. Algumas vezes, não saberemos a quantidade de elementos, alguma regra será definida para determinar a parada. No programa a seguir, definiremos valores para o vetor enquanto os valores forem maiores do que zero. 1 vetor = [] 2 i = 0 3 valor = int(input(f’Valor {i+1}: ’)) 4 while valor > 0: 5 i += 1 6 vetor.append(valor) 7 valor = int(input(f’Valor {i+1}: ’)) 8 print(f’Vetor definido: {vetor}’) Neste caso, como não sabemos a quantidade de elementos, tivemos que usar o laço while. A segunda forma de entrada, mais comum em nossos exerćıcios, é a partir da entrada de todos os elementos em uma única entrada do usuário em uma string e a chamada da função preencherVetor. No exemplo a seguir, fazemos isso para as frutas definidas no resumo desta prática: 1 from biblioteca import * 2 3 frutas = ’maçã, laranja, abacaxi’ 4 frutas = preencherVetor(frutas, ’str’) 5 quantidades = ’5, 3, 1’ 6 quantidades = preencherVetor(quantidades, ’int’) 7 for i in range(len(frutas)): 8 print(f’− Temos {quantidades[i]} unidades de {frutas[i]}’) Observe que os dois vetores devem possuir a mesma quantidade de elementos, fizemos um único laço for (pois conhecemos a quantidade de elementos) para imprimir valores dos dois vetores de forma conjunta (pois há uma relação entre eles pelo ı́ndice). É importante observar que utilizamos laços conforme a lógica da tarefa a ser cumprida, não é por estarmos manipulando dois vetores que devemos necessariamente fazer dois laços. 3 O programa anterior pode ser generalizado, fazendo o preenchimento dos doisvetores a partir de entradas do usuário. Para isso, basta substituir os valores fixados para as strings por input’s, um para cada vetor, aproveitamos para validar o tamanho dos vetores: 1 from biblioteca import * 2 3 frutas = input(’Nomes das frutas: ’) 4 frutas = preencherVetor(frutas, ’str’) 5 quantidades = input(’Quantidades das frutas: ’) 6 quantidades = preencherVetor(quantidades, ’int’) 7 if len(frutas) == len(quantidades): 8 for i in range(len(frutas)): 9 print(f’− Temos {quantidades[i]} unidades de {frutas[i]}’) 10 else: 11 print(’ERRO: Quantidade de elementos incompatível.’) Veja dois exemplos de execução: Exemplo 1: Nomes das frutas: banana, maçã, abacaxi, melão Quantidades das frutas: 4, 10, 8, 2 − Temos 4 unidades de banana − Temos 10 unidades de maçã − Temos 8 unidades de abacaxi − Temos 2 unidades de melão Exemplo 2: Nomes das frutas: banana, maçã, abacaxi, melão Quantidades das frutas: 10 ERRO: Quantidade de elementos incompatível. Implemente estes programas no Thonny e execute utilizando o depurador para entender perfeitamente o que eles fazem em detalhes. 4 Tarefa 2: Associação de valores e ı́ndices Como vimos, a relação entre ı́ndices e valores armazenados é muito importante na manipulação de vetores. Eventualmente, os elementos armazenados em um vetor podem representar os ı́ndices de interesse de um outro valor. Neste exemplo, ilustramos esta situação: 1 valores = [ 1, 5, 10, 4, 12, 6 ] 2 indices = [ 1, 4, 0, 2 ] 3 print(’Valores associados aos índices:’) 4 for i in range(len(indices)): 5 indice = indices[i] 6 valor = valores[indice] 7 print(f’Índice: {indice} >>> Valor: {valor}’) Observe que as variáveis indice e valor, dentro do laço, são dispensáveis: 1 valores = [ 1, 5, 10, 4, 12, 6 ] 2 indices = [ 1, 4, 0, 2 ] 3 print(’Valores associados aos índices:’) 4 for i in range(len(indices)): 5 print(f’Índice: {indices[i]} >>> Valor: {valores[indices[i]]}’) Porém, a criação das variáveis pode deixar o código mais “leǵıvel”, ou seja, mais fácil de ser compreendido. O mais importante é observar que a utilização dos valores armazenados nos vetores e o acesso a eles por intermédio de seus ı́ndices dependerá na natureza dos dados. Acessamos os valores do vetor valores acessando ı́ndices obtidos pelos dados contidos no vetor indices. Muitas vezes utilizamos algum recurso para possibilitar a manipulação de ı́ndices de acordo com alguma regra. No exemplo a seguir criaremos um vetor que conterá os ı́ndices de valores que respeitem a uma regra pré-definida: notas maiores do que 6. Em seguida imprimiremos os valores escolhidos. 1 from biblioteca import * 2 3 notas = input(’Valores das notas: ’) 4 notas = preencherVetor(notas, ’float’) 5 indices = [ ] 6 for i in range(len(notas)): 7 if notas[i] > 6: # a regra se aplica à nota, não ao índice 8 indices.append(i) # armazenamos o índice, não a nota! 9 10 print(’Notas selecionadas: ’) 11 for i in range(len(indices)): 12 print(f’− {notas[indices[i]]}’) Observe que, após a entrada e preenchimento das notas, primeiramente processamos as notas no laço da linha 7, neste laço, i representa ı́ndices do vetor notas, e usamos o laço para preencher o vetor indices com os valores de i que representam notas maiores do que 6 (a regra definida). Por outro lado, o segundo processamento tem a tarefa de imprimir apenas as notas selecionadas (que atendem à regra). Isto é feito no laço da linha 11, onde i representa ı́ndices do vetor indices, que são usados para permitir o acesso às notas. Neste programa a variável i é apenas uma variável auxiliar utilizada para fazer o processamento adequado de ı́ndices dos vetores manipulados a cada tarefa, depois de usada para processar um vetor, ela pode ser aproveitada para processar outro. 5 Veja alguns exemplos de execução: Exemplo 1: Valores das notas: 1, 2, 6, 6.5, 7, 7.8, 4, 5, 10 Notas selecionadas: − 6.5 − 7.0 − 7.8 − 10.0 Exemplo 2: Valores das notas: 1, 2, 6, 4, 5 Notas selecionadas: Implemente estes programas no Thonny e execute utilizando o depurador para entender perfeitamente o que eles fazem em detalhes. 6 Questão 1 Você deve implementar um programa que realiza a leitura das notas dos alunos de BCC701, preenchendo um vetor de valores reais (sempre haverá pelo menos uma nota). A partir deste vetor, você deve imprimir as seguintes estat́ısticas da turma: (i) maior nota; (ii) menor nota; (iii) média das notas. Para obter estes valores, você deve implementar a função estatNotas, que recebe o vetor de notas como argumento de entrada, calcula e retorna os três valores. Sendo assim, o seu programa principal seguirá o algoritmo: 1. Ler uma string com todos os valores do vetor; 2. Chamar a função preencherVetor (definida na Seção 7.3.3 do livro texto da disciplina); 3. Chamar a função estatNotas (implementada por você); 4. Imprimir os valores retornados pela função estatNotas no terminal (com uma casa decimal). Exemplo 1: Notas: 10 Maior nota: 10.0 Menor nota: 10.0 Nota média: 10.0 Exemplo 2: Notas: 1, 2, 3, 4, 5, 6, 7, 8 Maior nota: 8.0 Menor nota: 1.0 Nota média: 4.5 Exemplo 3: Notas: 10, 3.56, 9.9, 8.85, 7.45 Maior nota: 10.0 Menor nota: 3.6 Nota média: 8.0 7 Questão 2 Agora você vai criar uma nova versão do programa da questão 1, obtendo as notas dos alunos que estiverem acima da nota média calculada. Para isso, você implementará uma nova função: • acimaMedia: recebe como argumentos de entrada um vetor de notas e um valor de corte. A função cria um novo vetor, contendo os ı́ndices dos elementos que tiverem nota maior do que o valor de corte. Dica: crie um vetor vazio, depois avalie cada valor armazenado no vetor de entrada, se o valor em questão for maior que a média, adicione o ı́ndice correspondente no novo vetor. O programa passará a imprimir as notas acima da média, seguindo o algoritmo: 1. Executar os passos 1 a 4 do algoritmo da questão 1. 2. Chamar a função acimaMedia (implementada por você) passando como argumento o vetor de notas e a média das notas obtida no passo 3 do algoritmo da questão 1, e recebendo o vetor resultante; 3. Imprimir cada ı́ndice e nota que estiver acima da média, usando os vetores de ı́ndices e de notas. Observe que é necessário formatar as notas para uma casa decimal. Exemplo 1: Notas: 10 Maior nota: 10.0 Menor nota: 10.0 Nota média: 10.0 Notas acima da média: Exemplo 2: Notas: 1, 2, 3, 4, 5, 6, 7, 8 Maior nota: 8.0 Menor nota: 1.0 Nota média: 4.5 Notas acima da média: − [4] = 5.0 − [5] = 6.0 − [6] = 7.0 − [7] = 8.0 Exemplo 3: Notas: 10, 3.56, 9.9, 8.85, 7.45 Maior nota: 10.0 Menor nota: 3.6 Nota média: 8.0 Notas acima da média: − [0] = 10.0 − [2] = 9.9 − [3] = 8.8 8 Questão 3 Seu programa está fazendo tanto sucesso que agora você vai aprimorá-lo ainda mais, adaptando o programa da questão 2. Além de ler as notas dos alunos em um vetor, você também vai ler os nomes dos alunos em um outro vetor. Para cada nota acima da média impressa no terminal, você também vai imprimir o nome do aluno. Dica: os dois vetores – de notas e de nomes – estão associados pelos seus ı́ndices e, portanto, a nota do primeiro aluno e seu nome estarão no ı́ndice 0 dos dois vetores, enquanto as do segundo aluno estarão no ı́ndice 1, e assim por diante. Além disso, ao final do semestre, deve-se indicar quais alunos têm direito ao Exame Especial: aqueles com nota entre 3 (inclusive) e 6 (exclusive). Com isso, você vai implementar a função exameEspecial, que recebe o vetor de notas como argumento de entrada e retorna um novo vetor, contendo apenas os ı́ndices das notas que forem ≥ 3.0 e < 6.0. Você deve imprimir os dados de Exame Especial de forma similar aos das notas acima da média, incluindo, em ambos, os nomes dos respectivos alunos. Exemplo 1: Notas: 10 Nomes: João Maior nota: 10.0 Menor nota: 10.0 Nota média: 10.0 Notas acima da média: Notas em Exame Especial: Exemplo 2: Notas: 1, 2, 3, 4, 5, 6, 7, 8 Nomes: Baltazar, Rolando, Boneco,Zé, Cândida, Catifunda, Capitu, Ptolomeu Maior nota: 8.0 Menor nota: 1.0 Nota média: 4.5 Notas acima da média: − [4] = 5.0 (Cândida) − [5] = 6.0 (Catifunda) − [6] = 7.0 (Capitu) − [7] = 8.0 (Ptolomeu) Notas em Exame Especial: − [2] = 3.0 (Boneco) − [3] = 4.0 (Zé) − [4] = 5.0 (Cândida) Exemplo 3: Notas: 10, 3.56, 9.9, 8.85, 7.45 Nomes: Batman, Coringa, Sparrow, Smeagol, Chaves Maior nota: 10.0 Menor nota: 3.6 Nota média: 8.0 Notas acima da média: − [0] = 10.0 (Batman) − [2] = 9.9 (Sparrow) − [3] = 8.8 (Smeagol) Notas em Exame Especial: − [1] = 3.6 (Coringa) 9
Compartilhar