Mais uma vez faço uso de um pedido de um aluno para tentar fazer
pedagogia. Não sei se é o melhor caminho, até porque pode parecer que estou a reforçar a ideia de que se estuda resolvendo os problemas dos exames. Estes pedidos, que tenho recebido nos últimos dias (afinal o exame está à porta!!), levam-me a questionar sobre o nosso método de ensino e o vosso modo de aprender(?). No vosso caso, é claro que muitos são os que
não trabalham ao longo do ano. Na melhor das hipóteses assistem
passivamente às aulas e guardam depois uns dias antes do exame para se prepararem. E fazem-no tentando
decifrar fora de tempo os acetatos das aulas teóricas, e
olhando para as soluções de provas anteriores. No melhor dos casos, tentam resolver à vossa maneira, com imensas dificuldades e com muito não saber. Assim não se aprende! Na melhor das hipóteses passa-se no exame, mas não se aprende. Hoje é véspera de exame e, por isso, vou esquecer as minhas metafísicas.
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:
01.
def
exame(ficheiro):
02.
dic
=
{}
03.
lista
=
[]
04.
string
=
''
05.
abrir
=
open(ficheiro,
"r"
)
06.
string
+
=
abrir.read()
07.
lista.append(string.split())
08.
09.
for
palavra
in
range(len(lista)):
10.
dic[palavra]
=
lista[palavra]
11.
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:
1.
def
exame(ficheiro):
2.
3.
4.
return
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.
2.
f_in
=
open(ficheiro, ‘r’)
3.
lista_palavras
=
f_in.read().split()
Segundo comentário sobre a solução apresentada. Qual o sentido de fazer:
1.
string
=
‘’
2.
string
+
=
abrir.read()
ou de fazer:
1.
lista
=
[]
2.
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:
1.
2.
por cada palavra em lista de palavras:
3.
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:
1.
dic
=
{}
2.
for
palavra
in
lista_palavras:
3.
comp
=
len(palavra)
4.
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:
1.
def
exame_ec(ficheiro):
2.
f_in
=
open(ficheiro,
'r'
)
3.
lista_palavras
=
f_in.read().split()
4.
dic
=
{}
5.
for
palavra
in
lista_palavras:
6.
comp
=
len(palavra)
7.
dic[comp]
=
dic.get(comp, [])
+
[palavra]
8.
return
dic
E pronto! A complexidade domina-se com método, conhecimento e ... muita prática!