Solução para a provinha do Google Developer Day 2011 em Python
Esse ano, resolvi tratar com um pouco mais de respeito a prova do GDD. Ano passado, eu resolvi com o prompt do Python aberto, olhando o browser em uma janela e o prompt na outra. Esse ano, as perguntas eram um pouco mais trabalhosas e as strings maiores e isso me fez, em vez disso, escrever um programa. Mais tarde eu coloco o programa no github, mas, por hora, eu transcrevo e comento aqui a minha solução.
A prova apresenta dois textos escritos no idioma Googlon, com os quais vamos trabalhar, e quatro perguntas. Para ajudar (eles são realmente bonzinhos), eles dão as soluções para o primeiro texto, o que ajuda a testar se o código está correto.
Letras foo, bar e preposições
A primeira pergunta explica que algumas letras são chamadas de "letras foo" e todas as demais, "letras bar" e que preposições são palavras de cinco letras que começam com uma letra bar e não contém a letra "q" (é muito provável que a sua prova seja diferente da minha e que elas sejam geradas aleatoriamente - é como eu faria). Para ajudar a resolver, eu escrevi algumas funções
def foo(l): return l in "snrbg" def bar(l): return not foo(l) def preposicao(p): return len(p) == 5 and bar(p[-1]) and 'q' not in p
Aí, testar a resposta dada no enunciado é fácil:
>>> palavras_a = texto_a.split(' ') >>> len(filter(preposicao, palavras_a)) 63
Assim como responder a pergunta:
>>> palavras_b= texto_b.split(' ') >>> len(filter(preposicao, palavras_b)) 57
Verbos e verbos em primeira pessoa
A segunda pergunta ensina que verbos são palavras de 6 letras que terminam em uma letra bar. Se ele também começar com uma letra bar, estará em primeira pessoa.
def verbo(p): return len(p) >= 6 and bar(p[-1]) def verbo_primeira_pessoa(p): return verbo(p) and bar(p[0])
Agora podemos testar nosso código com o dado do enunciado:
>>> len(filter(verbo, palavras_a)) == 216 True >>> len(filter(verbo_primeira_pessoa, palavras_a)) == 160 True
E descobrir a nossa própria resposta:
>>> len(filter(verbo, palavras_b)) 224 >>> len(filter(verbo_primeira_pessoa, palavras_b)) 154
No meu caso, eu tinha 224 verbos, dos quais 154 em primeira pessoa.
Vocabulário
Agora o problema pede para criar uma lista com o vocabulário, ordenado segundo o alfabeto googlon. Para isso, eu vou usar o ordenador que já vem embutido nas listas do Python e vou produzir uma função de comparação. Essa função pode ser facilmente plugada em seu próprio sort, se você quiser muito:
def cmp_googlon(p1, p2): v = 'jgptzmqskbclrhdfnvwx' for l1, l2 in zip(p1, p2): if v.index(l1) != v.index(l2): return v.index(l1) - v.index(l2) return len(p1) - len(p2)
E podemos testar com os dados do enunciado:
>>> vocabulario_a_unsorted = list(set(palavras_a)) >>> ' '.join(sorted(vocabulario_a_unsorted, ... cmp = cmp_googlon)) == vocabulario_a True
Nota: ao construir um set com as palavras do texto A, eu eliminei as repetições. Como objetos do tipo set não são ordenáveis, eu transformei o conjunto em uma lista.
Agora podemos encontrar nossa resposta:
>>> vocabulario_b_unsorted = list(set(palavras_b)) >>> vocabulario_b = ' '.join(sorted(vocabulario_b_unsorted, cmp = cmp_googlon)) >>> vocabulario_b 'jgspd jgv jpgzkx jzvjw jmrmlq jmdxx jmntpzq jqw jspk jkc jbb jcphbk jch jcv jlkm...
Números
Agora a prova nos explica que todas as palavras em googlon tem um valor numérico. Em googlon, os números são escritos do dígito menos significativo para o mais significativo e em base 20. Pra isso, precisamos de mais uma função:
def valor_numerico(p): v = 'jgptzmqskbclrhdfnvwx' vn = 0 i = 0 for c in p: vn += v.index(c) * (20 ** i) i += 1 return vn
que, podemos testar contra o enunciado:
>>> valor_numerico('blsmgpz') == 262603029 True
Essa parte está certa. Mas a pergunta pede para contarmos os números bonitos. Para eles, números bonitos são divisíveis por 5 e maiores que 492528.
def numero_bonito(p): return valor_numerico(p) > 492528 and (valor_numerico(p) % 5 == 0)
Agora podemos testar:
>>> len(filter(numero_bonito, vocabulario_a.split(' '))) == 75 True
E chegar na nossa resposta:
>>> len(filter(numero_bonito, vocabulario_b.split(' '))) 71
Conclusão
Foi difícil? Nem um pouco. Se você não conseguiu responder por conta própria, precisa estudar mais. Foi mais trabalhosa do que a do ano passado? Um pouco. Por outro lado, ela tinha informações suficientes para você poder testar suas próprias soluções - e isso ajudou quem teve mais problemas para resolver a prova a aprender alguma coisa. Prova boa é assim - você aprende enquanto faz.
Uma última observação: eu gosto de list comprehensions, mas também gosto de map, filter e reduce. O código fica mais limpo quando eles são bem empregados.