quarta-feira, 23 de março de 2011

O problema dos romanos

Olá, pessoal. Quanto tempo, hein?
Bom, após vários meses sem postar nada, aqui estou eu de novo pra falar sabe do que? Advinha, a resolução de um probleminha com o auxílio da linguagem Python.
O negócio é o seguinte: lá na Roma antiga, ao invés do pessoal usar os algarismos arábicos (i.e. 1, 2, ...), eles tinham sua própria forma de representar os números, por meio dos algarismos romanos. Daí, surgiu a ideia de eu criar uma função que recebesse um número inteiro como argumento e retornasse o seu correspondente romano.
Após algumas horas quebrando a cabeça, finalmente cheguei na lógica mais pythônica.

#!/usr/bin/python3.1
# coding: utf-8

__author__ = 'Luiz Augusto de M. Morais'
__date__ = '23.03.2011'
__version__ = '1.0.1'
__license__ = 'GPL'

romanos = {0: '', 1: 'I', 5: 'V', 10: 'X', 50: 'L', 100: 'C', 500: 'D', 1000: 'M'}

def converter(numero):
    """converter(numero) -> string
    A função converter recebe um número entre 0 e 4000 e o converte para
    seu número romano correspondente."""
    if 0 < numero <= 3999:
        romano = ''
        tamanho = len(str(numero)) - 1
        for algarismo in decompor(numero, tamanho):
            romano += romanizar(algarismo, 10 ** tamanho)
            tamanho -= 1
        return romano
    else:
        print('O número tem que estar no intervalo: 0 < numero <= 3999')


def decompor(numero, tamanho):
    """decompor(numero, tamanho) -> lista de algarismos
    A função decompor recebe um número como parâmetro e retorna as partes
    deste número (i.e. dezena, centena, etc.) em forma de lista.
    O parâmetro tamanho se refere ao tamanho do número (e.g. 100 -> 3)"""
    algarismos = []
    for digito in str(numero):
        algarismos.append(int(digito) * 10 ** tamanho)
        tamanho -= 1
    return algarismos
        

def romanizar(numero, ordem=1):
    """romanizar(numero [, ordem]) -> string
    A função romanizar recebe um número inteiro como parâmetro e
    retorna o número romano correspondente."""
    if numero in romanos.keys():
        romano = romanos[numero]
    elif numero < 4 * ordem:
        romano = numero // ordem * romanos[ordem]
    elif numero == 4 * ordem:
        romano = romanos[1 * ordem] + romanos[5 * ordem]
    elif numero < 9 * ordem:
        romano = romanos[5 * ordem] + (numero // ordem - 5) * romanos[ordem]
    elif numero == 9 * ordem:
        romano = romanos[ordem] + romanos[ordem * 10]
    return romano

sexta-feira, 24 de dezembro de 2010

Qual a diferença entre #!/usr/bin/python e #!/usr/bin/env python?


Para quem utiliza o Linux como SO e programa em Python, já deve estar familiarizado em colocar um comentário com um caminho para o interpretador.

Este comentário especial na primeira linha faz com que o computador saiba onde está o interpretador da linguagem Python.

Mas, se você já prestou atenção, alguns programadores utilizam #!/usr/bin/python e outros #!/usr/bin/env python. Qual dos dois está certo? E qual a diferença entre eles? Eu também já fiz estas perguntas.

No primeiro caso, quando utilizamos #!/usr/bin/python, estamos especificando a localização do interpretador Python em sua máquina. O caminho está dizendo que o interpretador Python está dentro da pasta /usr/bin, que é onde geralmente ele está.

Mas, imagine se você fosse executar seu script em uma máquina que o interpretador estivesse instalado em /bin? O seu script simplesmente não iria funcionar, pois o caminho para o interpretador é diferente. O comando env resolve este problema.

Quando utilizamos #!/usr/bin/env python, estamos invocando o comando env, que procura o caminho do comando passado como argumento (i. e. python) nas variáveis de ambiente para poder executá-lo. Ou seja, se o interpretador estiver em /usr/local/bin, /bin/, /usr/bin ou em qualquer outro caminho, o comando env irá encontrá-lo e executá-lo, não importa onde ele esteja.

Portanto, quando for criar scripts em Python no Linux, escolha sempre a segunda opção para não ter dores de cabeça posteriormente.

terça-feira, 14 de dezembro de 2010

Matrizes em Python

Olá, pessoal. Depois de longos dias sem posts, aqui estou eu transmitindo mais um pouco do meu ínfimo conhecimento sobre Python a vocês.

Hoje nós vamos estudar maneiras de como criar e manipular matrizes em Python. Primeiramente, quero dizer que não vou utilizar o módulo SciPy e sim os artifícios nativos da linguagem, pois este post tem um caráter didático. Porém, se você estiver interessado em aplicações mais "profissionais", indico utilizar o módulo citado anteriormente, pois ele é bastante eficiente.

Revisando matrizes...

Na matemática, uma matriz é uma tabela composta de m x n elementos, onde m é o número de linhas e n o de colunas.
Existem vários tipos de matrizes. Veja abaixo os principais:

Matriz quadrada: o número de linhas é igual ao número de colunas.
Ex.:
[3, 1,        [1, 2, 3,
 2, 5]         4, 5, 6,
                7, 8, 9]

Matriz transposta: é uma matriz onde todos os elementos das linhas de M são transformados em colunas de Mt.
Ex.:
[1, 2, 3,      ==>      [1, 4,
 4, 5, 6]                    2, 5,
                               3, 6]

Matriz identidade: é uma matriz quadrada onde todos os elementos da diagonal principal são iguais a 1 e as demais posições iguais a 0.
Ex.:
[1, 0, 0,
 0, 1, 0,
 0, 0, 1]

Operações com matrizes

Soma de matrizes
[1, 0,      +      [2, 3,      =      [3, 3,
 5, 2]               4, 2]               9, 4]
Subtração de matrizes
[1, 0,      -       [2, 3,      =      [-1, -3,
 5, 2]               4, 2]                 1, 0]
Multiplicação por escalar
2   *   [1, 0,      =       [2, 0,
          5, 2]               10, 4]
Multiplicação de matrizes
Clique aqui para ver exemplos de multiplicação de matrizes.
Se quiser saber mais sobre matrizes, clique aqui.

Como utilizar matrizes em Python?

Listas
A forma mais rápida e fácil de utilizar matrizes em Python é criando listas aninhadas.
Veja o exemplo abaixo da representação de uma matriz 3 x 2 em Python.

matriz3x2 = [[4, 5, 1],
             [3, 2, 7]]

Como vocês podem ver, esta matriz nada mais é do que uma lista que contém listas. Estas listas mais internas estão representando as linhas e as colunas são representadas pelos elementos dos índices de cada linha.

Nesta matriz, as linhas são selecionadas pelo primeiro e as colunas pelo segundo índices.
Por exemplo, se eu quiser selecionar a segunda linha da matriz, utilizo o comando abaixo:
matriz3x2[1]
#Saída: [3, 2, 7]
Coloco o índice 1, ao invés de 2, pois os índices das listas em Python começam do número 0.

Mas, se eu quiser acessar um elemento específico da matriz, tenho que utilizar o índice da linha e o da coluna:
matriz3x2[1][2]
#Saída: 7

List Comprehensions
Se você ainda não sabe usar list comprehensions, clique aqui e aqui.

Você pode utilizar este artifício em Python para extrair uma coluna específica de uma matriz, por exemplo.
Ex.:
coluna2 = [linha[1] for linha in matriz3x2]
print coluna2
#Saída: [5, 2]

Um outro exemplo de list comprehensions em matrizes é capturar os elementos da diagonal principal.
Ex.:
matriz2x2 = [[4, 5],
             [3, 2]]
             
diagonal_principal = [matriz[i][i] for i in (0, 1)]
print diagonal_principal
#Saída: [4, 2]
Dicionários
Existe ainda outra forma de manipular matrizes em Python, é por meio de dicionários.
Esta abordagem é mais utilizada quando a matriz é esparsa, ou seja, a maioria dos seus elementos é igual a zero.
Poderíamos ter uma matriz usando listas assim:
matriz4 = [[4, 0, 0, 0, ],
             [0, 0, 0, 2, ],
             [0, 6, 0, 0, ],
             [0, 0, 0, 3, ]]

print matriz4[1][3]
#Saída: 2
Perceba que a maioria dos elementos da matriz são zeros. Ela pode ser otimizada se forem usados dicionários ao invés de listas.
Ex.:
matriz4dic = {(0,0): 4, (1, 3): 2, (2, 1): 6, (3,3): 3}
print matriz4dic[1, 3]
#Saída: 2
Esta matriz tem os mesmo elementos da matriz anterior, retirando somente os zeros.

Porém, se você tentar acessar uma posição onde não existe chave, será lançado um erro:
>>> matriz4dic[0,1]
Traceback (most recent call last):
  File "", line 1, in 
KeyError: (0, 1)

Para resolver isto, você só precisa utilizar o método get():
matriz4dic.get((0,1), 0)
0

O primeiro argumento é a posição do elemento na matriz e o segundo argumento é o valor que deve ser retornado caso a chave requerida não exista. Pronto, nosso problema está resolvido.

Espero que vocês tenham gostado das dicas. Qualquer dúvida, deixem um comentário abaixo.

Referências:
Aprenda Computação com Python
Learning Python, 3.ed.