MAC2166 - Introdução à Computação

06/05/2014 - Aula 11

O valor especial None

Python possui um valor especial, o None, que pode ser usado para representar a ausência de valor.

O None é útil, por exemplo, quando queremos indicar que uma dada posição de uma lista está vazia (ou seja, não possui um valor associada a ela). O tipo do valor None é NoneType; aliás, ele é o único valor existente desse tipo.

Veja os exemplos a seguir:

In [1]:
valor = None
print(valor, "-->", type(valor))
lista = [1,2,3,None,5,None]
print(lista," --> tamanho da lista:",len(lista))
None --> <class 'NoneType'>
[1, 2, 3, None, 5, None]  --> tamanho da lista: 6

Importante: Não confundir o valor especial None com as strings "None" ou "none". O valor especial é escrito sem aspas e com a primeira letra em maiúsculo.

In [2]:
valor1 = "None"   # Essa é uma string, não é o valor especial None
print("Tipo do valor 1:", type(valor1))
valor2 = None     # Esse é o valor especial None
print("Tipo do valor 2:", type(valor2))
valor1 == valor
Tipo do valor 1: <class 'str'>
Tipo do valor 2: <class 'NoneType'>

Out[2]:
False

Não podemos fazer operações matemáticas envolvendo o None como operador (ele não é equivalente ao valor zero!). Veja a seguir um exemplo de erro gerado quando tentamos fazer operações matemáticas com o None:

In [3]:
valor1 = 12
valor2 = None
valor1 + valor2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-8252db275da0> in <module>()
      1 valor1 = 12
      2 valor2 = None
----> 3 valor1 + valor2

TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

Quando precisamos fazer operações matemáticas envolvendo os elementos de uma lista que pode conter posições com o valor None, então é sempre preciso verificar o valor antes de envolvê-lo em algum cálculo, como mostrado no exemplo a seguir:

In [4]:
lista = [1,2,3,None,5,None]
# vamos fazer um laço para somar os elementos da lista
soma = 0
for elemento in lista:
    if elemento != None:  # só soma o elemento se ele não for None
        soma += elemento
print(soma)
11

Problema 21

Compute a matriz de campo minado (minesweeper)

  1. Escreva uma função que recebe como parâmetros uma matriz inteira Anxm, e uma posição (i,j) da matriz, e conta quantas posições ao redor da posição (i,j) contém o valor -1.

  2. Escreva um programa que lê uma matriz Anxm de 0's (posições livres) e -1's (minas). Utilizando a função do item anterior, o programa deve computar e imprimir a quantidade de minas ao redor de cada posição livre da matriz.

Exemplo

Para a matriz

0 0 0 0 0
0 -1 -1 -1 0
0 0 0 0 0
0 0 -1 0 0

a saída deve ser:

1 2 3 2 1
1 -1 -1 -1 1
1 3 4 3 1
0 1 -1 1 0

Solução 1 (sem moldura)

In []:
def main():
    m = int(input("Digite o número de linhas da matriz A: "))
    n = int(input("Digite o número de colunas da matriz A: "))
    A = le_matriz(m,n)

    print("Matriz lida:")
    imprime_matriz(A)

    for i in range(m):
        for j in range(n):
            if A[i][j] == 0:
                A[i][j] = conta_minas(A,i,j)
                
    print("Matriz de resultado:")
    imprime_matriz(A)   

def conta_minas(matriz, i, j):
    """
    (list, int, int) --> int
    Função que recebe como parâmetro uma matriz e uma posição (i,j)
    dessa matriz e devolve a quantidade de posições ao redor da posição
    (i,j) que contêm o valor -1 nessa matriz.

    """
    cont = 0
    
    # Verifica a posição à esquerda
    if j-1 >= 0 and matriz[i][j-1] == -1:
        cont +=1

    # Verifica a posição à direita
    if j+1 < len(matriz[i]) and matriz[i][j+1] == -1:
        cont +=1

    # Verifica as posições acima
    if i-1 >= 0:
        if matriz[i-1][j] == -1:
            cont +=1
        if j-1 >= 0 and matriz[i-1][j-1] == -1:
            cont +=1
        if j+1 < len(matriz[i]) and matriz[i-1][j+1] == -1:
            cont +=1

    # Verifica as posições abaixo
    if i+1 < len(matriz):
        if matriz[i+1][j] == -1:
            cont +=1
        if j-1 >= 0 and matriz[i+1][j-1] == -1:
            cont +=1
        if j+1 < len(matriz[i]) and matriz[i+1][j+1] == -1:
            cont +=1
    
    return cont

def le_matriz(m, n):
    """
    (int, int) --> list
    
    Função que recebe como entrada um número de linhas m
    e um número de colunas n e então lê uma matriz de inteiros
    tamanho m x n, ou seja, uma lista contendo m listas
    com n elementos cada. A matriz lida é devolvida como
    valor de retorno da função. 
    """

    print("Digite os elementos da matriz de tamanho %dx%d:" %(m,n))
    matriz = []
    for i in range(m):
        matriz.append([])
        for j in range(n):
            elemento = int(input("Elemento da %da. linha, %da. coluna: " %(i+1,j+1)))
            matriz[i].append(elemento)
            
    return matriz

def imprime_matriz(matriz):
    """
    (list) --> None

    Função que recebe uma matriz como entrada, ou seja uma
    lista de listas, e então a imprime.
    A função não tem nenhum valor de retorno.
    """
    
    for linha in matriz:
        for elemento in linha:
            print("%2d" %elemento, end = " ")
        print()

 
################
main()

Solução 2 (com moldura)

In []:
def main():
    m = int(input("Digite o número de linhas da matriz A: "))
    n = int(input("Digite o número de colunas da matriz A: "))
    A = le_matriz_com_moldura(m,n)

    print("Matriz lida:")
    imprime_matriz_com_moldura(A)
    
    for i in range(1,m+1):
        for j in range(1,n+1):
            if A[i][j] == 0:
                A[i][j] = conta_minas(A,i,j)
                
    print("Matriz de resultado:")
    imprime_matriz_com_moldura(A)   

def conta_minas(matriz, i, j):
    """
    (list, int, int) --> int
    Função que recebe como parâmetro uma matriz com "moldura" de 0's e
    uma posição (i,j) dessa matriz e devolve a quantidade de posições
    ao redor da posição (i,j) que contêm o valor -1 nessa matriz.
    """
    cont = 0
    
    for a in range(-1,2):
        for b in range(-1,2):
            if matriz[i+a][j+b] == -1:
                cont +=1
            
    if matriz[i][j] == -1:
        cont -=1

    return cont

def le_matriz_com_moldura(m, n):
    """
    (int, int) --> list
    
    Função que recebe como entrada um número de linhas m
    e um número de colunas n e então lê uma matriz de inteiros
    tamanho m x n, ou seja, uma lista contendo m listas
    com n elementos cada, "emoldurada" com 0's. A matriz criada
    é devolvida como valor de retorno da função. 
    """

    print("Digite os elementos da matriz de tamanho %dx%d:" %(m,n))
    matriz = [[0] * (n+2)]
    for i in range(1,m+1):
        matriz.append([0])
        for j in range(n):
            elemento = int(input("Elemento da %da. linha, %da. coluna: " %(i,j+1)))
            matriz[i].append(elemento)
        matriz[i].append(0)    
    matriz.append([0] * (n+2)) 
    return matriz

def imprime_matriz_com_moldura(matriz):
    """
    (list) --> None

    Função que recebe uma matriz como entrada, ou seja uma
    lista de listas, e então a imprime, sem mostrar a "moldura".
    A função não tem nenhum valor de retorno.
    """
    
    for i in range(1,len(matriz)-1):
        for j in range(1,len(matriz[i])-1):
            print("%2d" %matriz[i][j], end = " ")
        print()

        
################
main()

Problema 22

  1. Escreva uma função que recebe como parâmetros uma matriz real Anxm, e uma posição (i,j) da matriz, e calcula a média aritmética dos vizinhos de (i,j), ou seja, a média entre A[i-1][j], A[i+1][j], A[i][j-1] e A[i][j+1]. Desconsidere os vizinhos que não pertencem a matriz (por exemplo, os vizinhos de (0,0) são somente (0,1) e (1,0)).

  2. Escreva uma função que recebe como parâmetro uma matriz real Anxm e devolve uma matriz Amédia, onde Amédia[i][j] é a média aritmética dos vizinhos de (i,j). Para isto, utilize a função do item anterior.

  3. Escreva um programa que lê uma matriz real Anxm, e um número inteiro k; utilizando a função do item anterior, o programa deve transformar a matriz k vezes, imprimindo a matriz inicial e depois de cada transformação.

Obs.: Este problema corresponde ao exercício 13 da lista de exercícios sobre funções - Parte III.

Solução

In []:
def main():
    m = int(input("Digite o número de linhas da matriz A: "))
    n = int(input("Digite o número de colunas da matriz A: "))
    A = le_matriz(m,n)
    k = int(input("Digite o numero k de transformacoes em A:"))

    print("Matriz lida:")
    imprime_matriz(A)

    for i in range(k):
        A = matriz_media(A)        
        print("Matriz de resultado (transformaçao %d:" %(k+1))
        imprime_matriz(A)
    
def media_vizinhos(A,i,j):
    """
    (list,int,int) --> float
    Função que recebe uma matriz e um posição (i,j) desta matriz e
    devolve a média dos valores das posições ao redor de (i,j).
    """
    cont = 0
    soma = 0
    # Soma o valor da posição à esquerda
    if j-1 >= 0:
        cont +=1
        soma += A[i][j-1]

    # Soma o valor da posição à direita
    if j+1 < len(A[i]):
        cont +=1
        soma += A[i][j+1]

    # Soma o valor da posição acima
    if i-1 >= 0:
        cont +=1
        soma += A[i-1][j]

    # Soma o valor da posição abaixo
    if i+1 < len(A):
        cont +=1
        soma += A[i+1][j]
    
    return soma/cont

def matriz_media(A):
    """
    (list) --> list
    Função que recebe uma matriz A de reais e devolve uma nova matriz
    onde cada posição (i,j) possui o valor da média dos valores dos
    vizinhos da posição (i,j) em A.
    """
    A_media = []
    for i in range(len(A)):
        A_media.append([])
        for j in range(len(A[i])):
            A_media[i].append(media_vizinhos(A,i,j))
    return A_media


def le_matriz(m, n):
    """
    (int, int) --> list
    
    Função que recebe como entrada um número de linhas m
    e um número de colunas n e então lê uma matriz de reais
    tamanho m x n, ou seja, uma lista contendo m listas
    com n elementos cada. A matriz lida é devolvida como
    valor de retorno da função. 
    """

    print("Digite os elementos da matriz de tamanho %dx%d:" %(m,n))
    matriz = []
    for i in range(m):
        matriz.append([])
        for j in range(n):
            elemento = float(input("Elemento da %da. linha, %da. coluna: " %(i+1,j+1)))
            matriz[i].append(elemento)
            
    return matriz

def imprime_matriz(matriz):
    """
    (list) --> None

    Função que recebe uma matriz real como entrada, ou seja uma
    lista de listas, e então a imprime.
    A função não tem nenhum valor de retorno.
    """
    
    for linha in matriz:
        for elemento in linha:
            print("%4.2f" %elemento, end = " ")
        print()

##########
main()

Problema Extra

  1. Faça uma função que recebe como entrada uma matriz de inteiros Anxn e devolve três inteiros: k, Lin e Col. O inteiro k é um maior elemento de A e é igual a A[Lin,Col].

Obs.: Se o elemento máximo ocorrer mais de uma vez, indique em Lin e Col qualquer uma das possíveis posições.

Exemplo

Se A =
3 7 1
1 2 8
5 3 4

então k = 8, Lin =1 e Col = 2.

  1. Faça um programa que, dado um inteiro n e uma matriz quadrada de ordem n, cujos elementos são todos inteiros positivos, imprime uma tabela onde os elementos são listados em ordem decrescente, acompanhados da indicação de linha e coluna a que pertencem. Havendo repetições de elementos na matriz, a ordem é irrelevante. Utilize obrigatoriamente o procedimento da parte (a).

Exemplo

No caso da matriz acima, a saída poderia ser:
Elem Linha Coluna
8 1 2
7 0 1
5 2 0
4 2 2
3 0 0
3 2 1
2 1 1
1 0 2
1 1 0

Solução

In []:
def main():
    m = int(input("Digite o número de linhas da matriz A: "))
    n = int(input("Digite o número de colunas da matriz A: "))
    A = le_matriz(m,n)

    print("Matriz lida:")
    imprime_matriz(A)

    print()
    print("Elem\tLinha\tColuna")
    maior,i,j = maior_elemento(A)
    while maior > -1:
        print("%3d\t%3d\t%3d" %(maior,i+1,j+1))
        A[i][j] = -1
        maior, i, j = maior_elemento(A)
    
def maior_elemento(L):
    """
    (list) --> int, int, int
    Funçao que recebe como parametro uma matriz e devolve
    o elemento de maior valor na matriz e sua posiçao (i,j)
    """
    maior = L[0][0] 
    i_maior = 0
    j_maior = 0
    for i in range(len(L)):
        for j in range(len(L[i])):
            if L[i][j] > maior:
                maior = L[i][j]
                i_maior = i
                j_maior = j
    return maior, i_maior, j_maior
    
def le_matriz(m, n):
    """
    (int, int) --> list
    
    Função que recebe como entrada um número de linhas m
    e um número de colunas n e então lê uma matriz de inteiros
    tamanho m x n, ou seja, uma lista contendo m listas
    com n elementos cada. A matriz lida é devolvida como
    valor de retorno da função. 
    """

    print("Digite os elementos da matriz de tamanho %dx%d:" %(m,n))
    matriz = []
    for i in range(m):
        matriz.append([])
        for j in range(n):
            elemento = int(input("Elemento da %da. linha, %da. coluna: " %(i+1,j+1)))
            matriz[i].append(elemento)
            
    return matriz

def imprime_matriz(matriz):
    """
    (list) --> None

    Função que recebe uma matriz como entrada, ou seja uma
    lista de listas, e então a imprime.
    A função não tem nenhum valor de retorno.
    """
    
    for linha in matriz:
        for elemento in linha:
            print("%3d" %elemento, end = " ")
        print()

##########
main()

Uma "prévia" sobre strings (para ajudar na resolução do EP3)

Strings (valores do tipo do str) têm muitas semelhanças com listas. Uma string pode ser vista como uma lista onde cada posição contém um caracter.

Assim como fazemos com listas, nós podemos:

Veja os exemplos a seguir:

In [5]:
texto = "A minha matéria favorita é MAC2166"
print("Texto completo: %s" %(texto))
print("O texto possui %d caracteres" %len(texto))
print("O caracter na posição 3 do texto é:", texto[2])
print("O trecho de texto entre as posições 6 e 14 é:", texto[6:15])
Texto completo: A minha matéria favorita é MAC2166
O texto possui 34 caracteres
O caracter na posição 3 do texto é: m
O trecho de texto entre as posições 6 e 14 é: a matéria

Embora possamos acessar o seu valor, não podemos modificar uma posição específica de uma string usando indexação. Strings em Python são imutáveis. Essa é uma diferença importante entre strings e listas. Veja o exemplo abaixo:

In [6]:
poeminha = "Betatinha quando dorme, espalha a rama pelo chão"
poeminha[1] = "a"
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-7a95dff50d37> in <module>()
      1 poeminha = "Betatinha quando dorme, espalha a rama pelo chão"
----> 2 poeminha[1] = "a"

TypeError: 'str' object does not support item assignment

Há diferentes formas de se converter valores numéricos em strings. A mais direta delas é por meio da função str(), como mostrado nos exemplos a seguir:

In [7]:
num_dois = 2
print(num_dois, "-->", type(num_dois))
str_dois = str(num_dois)   # converte o valor em num_dois para string e armazena-o em str_dois
print(str_dois, "-->", type(str_dois))
2 --> <class 'int'>
2 --> <class 'str'>

In [8]:
str_real = str(3.33333333333)
print(str_real, "-->", type(str_real))
3.33333333333 --> <class 'str'>

Uma outra forma de converter números em strings é por meio de strings de formatação, como as que frequentemente usamos nos comandos print e input, nos exercícios que fazemos em aula. Veja exemplos a seguir:

In [9]:
num_real1 = 13.2278430
num_real2 =  4.9
num_int1 = 121
num_int2 = 6
str_reais_formatados = "Números reais formatados: |%6.3f|, |%6.3f|" %(num_real1, num_real2)
print(str_reais_formatados)
str_ints_formatados = "Números inteiros formatados: |%4d|, |%4d|" %(num_int1, num_int2)
print(str_ints_formatados)
str_num_simples = "%d" %(num_int1)
print(str_num_simples, "-->", type(str_num_simples))
Números reais formatados: |13.228|, | 4.900|
Números inteiros formatados: | 121|, |   6|
121 --> <class 'str'>

Uma função útil na manipulação de strings é a split(), que cria uma lista de strings a partir de uma só string. Essa função pode ser chamada por meio da notação de ponto, a partir de um objeto do tipo str. A função recebe como parâmetro o caracter (ou a string) que será usada como separador de substrings dentro da string a ser "desmembrada". Parece complicado, mas não é! Veja os exemplos a seguir:

In [10]:
texto = "Passarim quis pousar, não deu, voou"
palavras = texto.split(" ")   # usa o caracter de espaço como separador de substrings   
print(palavras)
['Passarim', 'quis', 'pousar,', 'não', 'deu,', 'voou']

In [11]:
outro_texto = "Este é um string"
pedacos = outro_texto.split("t")  # usa "t" como caracter separador
print(pedacos) 
['Es', 'e é um s', 'ring']

O operador + (de concatenação) pode ser aplicado tanto a listas quanto a strings. O primeiro exemplo a seguir mostra um caso de uso envolvendo listas, enquanto o segundo exemplo se refere à concatenação de strings:

In [12]:
lista1 = [1,2,3]
lista2 = [9,8,7,6,5]
lista3 = lista1 + lista2 # cria uma nova lista contendo os elementos de lista1 e lista2
print(lista3)
[1, 2, 3, 9, 8, 7, 6, 5]

In [13]:
verso1 = "Como diria o Cebolinha: "
verso2 = "- Keep calm and make an infallible plan!"
citacao = verso1 + verso2  # cria uma nova string com a junção de verso1 e verso2
print(citacao)
Como diria o Cebolinha: - Keep calm and make an infallible plan!

Tópicos vistos na Aula 11

Referências e outros materiais para estudo