No exame normal, o problema 4 pedia para ler um ficheiro de texto e construir um dicionário em que as chaves são inteiros e os valores a lista das palavras cujo comprimento é igual ao valor da chave. Este problema obriga a saber o que são e como se podem manipular ficheiros de texto e dicionários. Não é lendo apressadamente durante o exame o Manual do Python que estes conceitos se aprendem! Por isso é melhor praticar com exemplos. Em vários post recentes tratei precisamente de ficheiros de texto e de dicionários... Parece que sem sucesso! Mas vamos à solução que me foi enviada:
def exame(ficheiro):
dic={}
lista=[]
string=''
abrir=open(ficheiro,"r")
string+=abrir.read() #string sera a cadeia de caracteres contida no ficheiro#
lista.append(string.split()) #aqui divido a cadeia de caracteres numa lista e junto-a a 'lista'#
for palavra in range(len(lista)):
dic[palavra]=lista[palavra]
print dic
Dizia, e bem, o vosso colega que não funcionava correctamente, devolvendo apenas um dicionário com uma única chave (0) cujo valor associado era a lista de todas as palavras. Este tipo de erro indicia desde logo onde está o problema. Mas para ter essa percepção é preciso ter experiência de programação (e de erros!). Em vez de dizer já onde está o erro, olhemos para o problema e como o podemos resolver.
Vamos uma vez mais por partes. E neste problema a solução passa por dois subproblemas: (1) obter a lista das palavras e, (2)
a partir da lista das palavras construir o dicionário:
def exame(ficheiro):
# (1) obtém palavras
# (2) forma dicionário
return # dicionário
Primeiro comentário à solução: existem grosso modo dois modos de introduzir informação num programa (pelos parâmetros e por instruções de entrada) e dois modos de comunicar resultados (por return e por instruções de impressão). A escolha depende do problema e do que nos é pedido. Neste caso, era evidente que a entrada de dados era por parâmetro e a saída por return.
Passemos ao primeiro sub-problema. Um ficheiro é uma longa cadeia de caracteres, que vamos ter que ler e dividir em palavras.
# (1) obtém lista palavras
f_in = open(ficheiro, ‘r’)
lista_palavras = f_in.read().split()
Segundo comentário sobre a solução apresentada. Qual o sentido de fazer:
string = ‘’
string += abrir.read()
ou de fazer:
lista = []
lista.append(string.split())
Nenhum! Ainda por cima pode dar origem a erros. As associações entre nomes e objectos são feitas através da operação de atribuição, por exemplo a = 5. Só depois disto é que o nome existe no espaço de nomes, associado a objecto. Neste caso, se quero associar ao nome string a cadeia de caracteres do ficheiro, faço:
string = abrir.read()
e o mesmo para a lista:
lista = string.split()
Neste segundo caso está uma parte do erro do programa. É que, em vez de lista estar associada à lista das palavras, fica associada a uma lista que só tem um elemento que é a lista das palavras! Exemplificando, fica:
lista = [[‘toto’,‘abacadabra’]]
e não
lista = [‘toto’,‘abacadabra’]
uma maneira de resolver o problema seria fazer como no caso de string (feio, como já se disse, mas funcional):
lista = []
lista += string.split()
Tem que se perceber melhor os métodos. E, já agora, outra coisa. Os métodos têm uma sintaxe simples:
<objecto>.<método>(<argumentos>)
Aplico o método ao objecto, usando eventualmente argumentos. Mas qual é o resultado da aplicação?? Um objecto!!! Implicações? Podermos aplicar métodos em cadeia;
<objecto>.<método>(<argumentos>).<método>(<argumentos>)....<método>(<argumentos>)
como no exemplo acima:
lista_palavras = f_in.read().split()
Ao objecto ficheiro aplica-se o método read, que devolve um objecto que é uma cadeia de caracteres à qual se aplica o método split!!!
Agora é tempo de resolver a segunda parte. Para simplificar, vamos supor que não nos preocupam nem as palavras repetidas nem os eventuais sinas de pontuação. A solução que tem isto em conta está no post com a solução do exame.
Então o que temos que fazer:
# (2)
por cada palavra em lista de palavras:
acrescentar a palavra ao dicionário
Temos assim uma estratégia que envolve um ciclo. Quem controla o ciclo é o conteúdo da lista e não os índices (ver outro post recente sobre o assunto). Mas precisamos da chave também! Claro, mas isso é fácil: é que, por definição a chave é igual ao comprimento da palavra. E como acrescentamos? Existe a possibilidade de a chave já existir! Certo. Mas usando um get ( ver post recente sobre o assunto) podemos resolver as duas situações possíveis só com uma instrução. Logo o código:
dic = {}
for palavra in lista_palavras:
comp = len(palavra)
dic[comp] = dic.get(comp,[]) + [palavra]
Pergunta: porque é que, neste caso, temos que fazer primeiro dic = {}, e nos casos anteriores de string e lista não??
Terceiro comentário sobre o código apresentado. O ciclo é controlado pelos índices da lista de palavras (não é por colocar for palavra in ... que palavra é uma palavra!) Então, palavra, vai valer, 0, 1, 2,.... Essas serão as chaves do dicionário criado. Mas não é feita a ligação entre as palavras e o seu comprimento. O que se está a fazer é criar uma associação (chave: valor) = (indice da palavra na lista : palavra). Juntando este erro, ao outro já anteriormente referido e relacionado com o mau uso do append, vai dar algo como:
{0: [‘toto’,‘abacadabra’]}
Juntando agora todas as peças do puzzle:
def exame_ec(ficheiro):
f_in = open(ficheiro,'r')
lista_palavras = f_in.read().split()
dic = {}
for palavra in lista_palavras:
comp = len(palavra)
dic[comp] = dic.get(comp, []) + [palavra]
return dic
E pronto! A complexidade domina-se com método, conhecimento e ... muita prática!
Obrigado.
ResponderEliminarJuntando aos erros iniciais o facto de eu não ter percebido/memorizado o que o problema me pedia, tornou-se deveras mais difícil. Para piorar as coisas, estava a tentar criar um dicionário chaves 1,2,3,4,5 para a 1ª,2ª,3ª,4ª,5ª (...) palavras do ficheiro de texto.
Daí não conseguir safar-me com a resposta que o professou colocou online, anteriormente.