P2
O problema 2 pedia para criar um programa que transformasse uma cadeia de caracteres numa outra na qual a primeira ocorrência de um dado caractere fosse replicada um numero de vezes na nova cadeia igual à posição onde ocorre na cheia original mais um. Era necessário manter a ordem relativa das ocorrências dos diferentes caracteres. Este exercício tinha uma solução simples baseada no padrão tantas vezes trabalhado de ciclo - acumulador.
def mul_car(cadeia): cad = '' for i in range(1,len(cadeia)+1): elem = cadeia[i-1] if elem not in cad: cad += elem * i return cadcad é o acumulador onde vamos acrescentando às soluções parciais as ocorrências do novo caractere. notar a existência da condicional que serve para filtrar os caracteres individuais já utilizados.
Quem conhece Python de um modo mais profundo podia propor uma versão alternativa baseada em listas por compreensão: def mul_car2(cadeia): return ''.join([cadeia[i] * (i+1) for i in range(len(cadeia)) if cadeia[i] not in cadeia[:i]]) Note-se o desaparecimento explicito do acumulador e o modo como se transforma a lista resultado numa cadeia de caracteres.
P3
A sobreposição de duas imagens a preto e branco, representadas como listas de listas de uns e zeros não representa problema de maior. A sobreposição significa que basta que numa dada posição (um dado pixel) esteja a 1 (preto) o resultado na nova imagem deve também ser 1. Percorrendo naturalmente a imagem com dois ciclos for e alternado um a um chegamos ao resultado desejado.
def sobreposicao(img1, img2): nova_img = [] for i in range(len(img1)): nova_linha = [] for j in range(len(img1[0])): nova_linha.append(img1[i][j] or img2[i][j]) nova_img.append(nova_linha) return nova_imgTambém aqui podemos recorrer a listas por compreensão para obter um programa mais curto:
def sobreposicao2(img1,img2): return [ [(img1[i][j] or img2[i][j]) for j in range(len(img1[0]))] for i in range(len(img1))]Notar a existência de dois ciclos e como o ciclo mais interior aparece primeiro.
Turma TP2
P2
Anagrama é um conceito conhecido: palavras formadas por permutações das mesmas letras e em igual quantidade. O exemplo clássico em português é dado pelas palavras “roma” e “amor”. Uma solução ingénua para esta questão seria testar o igual comprimento das palavras e depois verificar se cada caractere de uma ocorre na outra.
def anagramas1(cad1,cad2): """versão errada!""" if len(cad1) != len(cad2): return False for elem in cad1: if elem not in cad2): return False return TruePara verificar que está errada basta testar com as palavras ‘aab’ e ‘bba’. Em vez de falso vai dar verdadeiro. O problema está no facto de o numero de ocorrência de cada caractere em cada uma das palavras ter que ser o mesmo. Daí que uma solução simples seja:
def anagramas2(cad1,cad2): if len(cad1) != len(cad2): return False for elem in cad1: if cad1.count(elem) != cad2.count(elem): return False return TrueClaro que podemos pensar em alternativas. Por exemplo, transformar as cadeias em listas, ordená-las e verificar se resulta em duas listas … iguais:
def anagramas3(cad1,cad2): list_cad1 = list(cad1) list_cad2 = list(cad2) list_cad1.sort() list_cad2.sort return list_cad1 == list_cad2Para os pitónicos puristas (peritos??) temos outra solução:
from collections import Counter def anagramas4(cad1, cad2): return Counter(cad1) == Counter(cad2)Counter é um typo que se pode definir como uma colecção não ordenada que implementada como um dicionário em que as chaves são os elementos e o valor o numero de ocorrências da chave. O conceito de dicionário será dado na próxima aula!
Quem não souber da existência de Counter pode implementar a sua solução:
def conta_elems(seq): conta = {} for elem in seq: counts[elem] = counts.get(elem, 0) + 1 return conta def anagramas4b(cad1, cad2): return conta_elems(cad1) == conta_elems(cad2)Parece que já temos mulitas alternativas e que dificilmente arranjaremos outra substancialmente diferente. Ou será que não??? Olhemos o código abaixo:
def anagramas5(cad1, cad2): return [False,True][sum([ord(x) for x in cad1]) == sum([ord(x) for x in cad2])]Experimente e … surpresa! Parece que funciona. Mas como? Como se pode ver usamos listas por compreensão para transformar cada lista na lista dos seus códigos numéricos. Esses códigos são somados e verificamos se são ou não iguais. O resultado por isso ou é True ou é False. Como disse nas aulas, True é representado por 1 e False por zero. Então o que temos no final é a forma [False,True][1] ou [False,True][0], isto é estamos a obter por indexação o elemento da lista [False,True] ou na posição zero (False) ou na posição um (True). Engenhoso, mas por ventura não muito claro e dependente do modo como estão implementados os booleanos.
P3
A intersecção de duas imagens é semelhante à sobreposição. A diferença agora é que devemos ter um apenas nas situações em que as duas imagens estejam, na mesma posição, iguais a um. Assim uma solução simples será:
def interseccao(img1, img2): nova_img = [] for i in range(len(img1)): nova_linha = [] for j in range(len(img1[0])): nova_linha.append(img1[i][j] and img2[i][j]) nova_img.append(nova_linha) return nova_imgTambém aqui podíamos recorrer a uma solução com listas por compreensão. Ao leitor o cuidado de o fazer.