Personal tools
You are here: Home



 
Showing blog entries tagged as: python

Fazendo um pouco melhor (ainda a provinha do GDD)

Ainda não desisti de resolver a prova do GDD em Erlang. Não. Não preciso resolver em Erlang, mas, com tanta gente usando Java, PHP e até PL/SQL pra resolvê-la (e com um amigo que usou Haskell), eu fiquei com vontade.

Também posso repetir uma do ano passado e fazê-la em Lisp.

Então. Erlang é avessa a loops. Loops fazem coisas mudarem de estado e linguagens funcionais não gostam que coisas mudem de estado. O dialeto de Lisp que eu usei ano passado também, mas faz uma concessão e me deixa fazê-los.

O comparador

Assim, a nossa primeira função com loop da prova, cmp_goog, que é assim:

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)

Ficaria assim:

def cmp_googlon(p1, p2):
    v = 'jgptzmqskbclrhdfnvwx'
    if p1 == p2: return 0
    elif len(p1) == 0 or len(p2) == 0: return len(p1) - len(p2)
    elif p1[0] == p2[0]: return cmp_googlon(p1[1:], p2[1:])
    else: return  v.index(p1[0]) - v.index(p2[0])

Note que, em vez de comparar as strings em um loop, eu comparo só seus primeiros elementos e, se os dois forem iguais, eu chamo o comparador de novo, agora com as strings sem a primeira posição.

Bases numéricas

A outra função serve para nos dar o valor em base 10 de um número em googlon. O original é um clássico, em que você percorre os dígitos do número e vai totalizando os valores de cada casa:

def valor_numerico(p):
    v = 'jgptzmqskbclrhdfnvwx'
    vn = 0
    i = 0
    for c in p:
        vn += v.index(c) * (20 ** i)
        i += 1
    return vn

A idéia é que o valor de um número é o valor do seu dígito menos significativo somado ao produto da base multiplicada pelo valor do resto. No caso de números em base 10, 123 é dado pela soma de 3 com o produto de 10 e 12, sendo que 12 é dado por 2 somado a 10 vezes 1. Transcrito em Python, a nova versão é bem mais concisa:

def valor_numerico_f(p):
    v = 'jgptzmqskbclrhdfnvwx'
    if len(p) == 1:
        return v.index(p)
    else:
        return v.index(p[0]) + 20 * valor_numerico_f(p[1:])

Agora eu preciso de algumas horas para escrever a versão em Erlang. Desejem-me sorte.

Read More…

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.

Read More…

Sobre a provinha do Google Developer Day 2011

Ano passado, quando a Google abriu as inscrições para o GDD, eu escrevi o primeiro de uma série de três artigos sobre a tal provinha. Esperei até o final das inscrições (e o sinal verde de um amigo que trabalha lá) para publicá-lo.

Não vou fazer diferente esse ano. Se você veio aqui querendo ver a solução dos problemas do ano passado, eles estão relacionados abaixo. Se, por outro lado, chegou aqui procurando um jeito fácil de entrar no evento, devia ter vergonha. Eu respeito a decisão da Google de usar a prova como uma forma de garantir que a platéia tenha melhores chances de entender o que o palestrante vai falar e não vou ajudar a estragar o processo de seleção de convidados deles. Quando as inscrições estiverem encerradas, eu volto aqui e publico a minha solução e aí você pode comparar com a sua.

De resto, boa sorte. A prova não é difícil e eu tenho certeza que você consegue. Você já chegou até aqui, afinal.

Um abraço e até lá.

Nota: Se você colocar aqui um comentário mostrando uma solução antes que sejam fechadas as inscrições, eu vou apagar pela mesma razão que me fez não publicar a minha ainda. Se você tem uma solução, volte depois.

Outra nota: Agora, que as inscrições estão encerradas, você pode achar soluções procurando no Google. Uma delas (em Java) foi postada em um comentário aqui. A mihha em Python está aqui. Há outras, algumas com escolhas de linguagem ainda mais estranhas do que a minha versão para computadores de 8-bits do ano passado. Acho uma pena que tantos tenham praticado GDD (Google-Driven Development, pun intended) e tenham googlado por respostas em vez de aprender a programar.

Read More…

Python 2.6, PIL, Django 1.3 e MySQLdb no CentOS 5.5

Posted by Ricardo Bánffy at Apr 11, 2011 05:05 PM |

Instalar um ambiente Django razoavelmente moderno em um CentOS 5.5 (e, presumivelmente, em um Red Hat 5.x) pode não ser uma tarefa trivial - envolve, por exemplo, algumas decisões que precisam ser tomadas e, às vezes, um ou outro sacrifício que precisa ser feito.

Read More…