2.16. Sequências

Uma sequência é um conjunto ordenado de \(n\) valores:

  • \(a_0, a_1, a_2, ..., a_{n-1}\)

Cada elemento de uma sequência é associado a um número chamado de índice ou posição. O primeiro índice é o zero.

Os três tipos básicos de sequências são:

  • Strings: sequência imutável de caracteres.

  • Tuplas: sequência imutável de valores (ou itens).

  • Listas: sequência de valores (ou itens), que pode crescer, encolher, ou alterar elementos.

Operações comuns com sequências:

Tabela 2.13 - Operações com sequências.
Fonte: The Python Standard Library [19].

Operador

Descrição

x in s

True se um item de \(s\) for igual a \(x\), False caso contrário.

x not in s

False se um item de \(s\) for igual a \(x\), True caso contrário.

s + t

Concatenação de \(s\) e \(t\).

s[i]

\(i\)-th item de \(s\).

s[i:j]

Parte da sequência no intervalo \([i,j)\).

len(s)

Comprimento da sequência \(s\).

min(s)

Menor item da sequência \(s\).

max(s)

Maior item da sequência \(s\).

s.index(x)

Índice da primeira ocorrência de \(x\).

s.count(x)

Número total de ocorrências de \(x\) em \(s\).

2.16.1. Strings

Como visto na Seção 2.14, strings são sequência imutáveis de caracteres:

>>> nome = "Introdução à Programação com Dados Geoespaciais"
>>> letra = "ç"
>>> if letra in nome:
...     print(f"Nome contém a letra '{letra}'!")
... else:
...     print(f"Nome não contém a letra '{letra}'!")
...
Nome contém a letra 'ç'!
>>> pos = nome.index(letra)
>>> print(pos)
>>> tamanho = len(nome)
>>> print(tamanho)

Nota

Para saber mais sobre strings, consulte a Seção 2.14.

2.16.2. Tuplas

As tuplas são expressas através de uma sequência cujos itens são separados por vírgula e delimitados ou não por parênteses. Vamos utilizar uma tupla para representar o par de coordenadas do centróide da cidade de São Paulo (Figura 2.19):

Trecho de Código 2.14 - Criando uma tupla para representar o centróide da cidade de São Paulo.
 1centroide_sp = (-46.7165, -23.6830)
 2
 3print(centroide_sp)
 4
 5print("longitude: {} latitude: {}".format(*centroide_sp))
 6
 7print(len(centroide_sp))
 8
 9longitude = centroide_sp[0]
10latitude = centroide_sp[1]
Centróide da cidade de São Paulo

Figura 2.19 - Centróide da cidade de São Paulo.

No Trecho de Código 2.14 podemos observar o seguinte:

  • A linha 01 cria uma tupla contendo dois valores em ponto flutuante e associa esse novo objeto ao nome (ou indentificador, ou variável) centroide_sp.

  • A linha 05 utiliza uma notação especial para descompactar (unpack) a tupla na chamada do método format. Dessa maneira os valores individuais da tupla são passados ao método format, que poderá então usá-los no lugar das marcações de substituição (placeholders) da string de formatação.

  • Na linha 07, usamos a função len, disponível para todos os tipos de sequência, para saber o número de elementos da tupla.

  • As linhas 09 e 10 utilizam o operador de índice (operador[]) para acessar os elementos da tupla. Repare que o primeiro elemento da tupla possui o índice 0.

Tuplas podem ser aninhadas (nested). No Trecho de Código 2.15, usamos uma tupla para representar o retângulo envolvente mínimo (REM ou Bounding Box) do polígono que define o limite (ou contorno, ou fronteira) da cidade de São Paulo (Figura 2.20). Veja que cada elemento da tupla, na linha 01, é também uma tupla, com as coordenadas do canto inferior esquerdo e superior direito desse retângulo.

Trecho de Código 2.15 - Criando uma tupla cujos elementos também são tuplas.
 1rem_sp = ( (-46.8254, -24.0084), (-46.3648, -23.6830) )
 2
 3canto_inferior_esquerdo = rem_sp[0]
 4
 5canto_superior_direito = rem_sp[1]
 6
 7xmin = canto_inferior_esquerdo[0]
 8
 9ymin = rem_sp[0][1]
10
11print(f"xmax: {rem_sp[1][0]}")
Retângulo envolvente mínimo do perímetro da cidade de São Paulo

Figura 2.20 - Retângulo envolvente mínimo do perímetro da cidade de São Paulo.

No Trecho de Código 2.14 ainda temos:

  • Na linha 03, o operador de índice (operador[]) é utilizado para acessar o primeiro par de coordenadas do retângulo envolvente. Podemos verificar que o elemento retornado por este operador também é uma tupla:

    >>> print(type(canto_inferior_esquerdo))
    <class 'tuple'>
    
  • Na linha 07, utilizamos novamente o operador de índice ([]) para acessar o valor de \(x_{min}\).

  • A linha 09 mostra que podemos usar o operador de índice de maneira encadeada, acessando o primeiro elemento da tupla mais externa e depois o valor do segundo elemento da tupla mais interna (\(y_{min}\)).

  • A linha 11 mostra como podemos usar elementos específicos da tupla dentro de uma string formatada.

Uma tupla é uma sequência imutável, isto é, se tentarmos alterar um item de uma tupla, uma exceção será lançada, como pode ser visto no trecho de código abaixo:

>>> centroide_sp[1] = 45.0
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

2.16.3. Listas

As listas são expressas através de uma sequência cujos itens são separados por vírgula e delimitados por colchetes. Vamos criar uma lista com o nome de algumas cidades:

>>> cidades = [ "São Paulo", "Rio de Janeiro", "Belo Horizonte", "Ouro Preto"]
>>> print(cidades)
['São Paulo', 'Rio de Janeiro', 'Belo Horizonte', 'Ouro Preto']

Nota

Podemos distribuir os elementos de uma lista em múltiplas linhas. A lista cidades, por exemplo, poderia ter sido definida da seguinte maneira:

>>> cidades = [
...    "São Paulo",
...    "Rio de Janeiro",
...    "Belo Horizonte",
...    "Ouro Preto"
... ]

Como uma lista é uma sequência mutável, existem operações que permitem modificar, por exemplo, a ordem de seus elementos. O método sort permite ordenar os elementos de uma lista:

>>> cidades.sort()
>>> print(cidades)
['Belo Horizonte', 'Ouro Preto', 'Rio de Janeiro', 'São Paulo']

Nota

O método sort não cria uma nova lista, ele realiza a alteração in-place. Para maiores informações sobre esse método, consulte [36].

Nota

Python oferece também uma função denominada sorted que permite criar uma lista ordenada a partir de uma sequência qualquer. A definição dessa função pode ser encontrada em [18]. Para criar uma nova lista de cidades “ordenada ao contrário”, faça:

>>> nova_lista = sorted(cidades, reverse=True)
>>> print(nova_lista)
['São Paulo', 'Rio de Janeiro', 'Ouro Preto', 'Belo Horizonte']

Veja que a lista original (cidades) continua com os elementos ordenados em ordem ascendente ou lexicográfica:

>>> print(cidades)
['Belo Horizonte', 'Ouro Preto', 'Rio de Janeiro', 'São Paulo']

Dica

Veja o seguinte tutorial sobre ordenação em Python [13].

Para adicionar um novo elemento ao final de uma lista, pode-se utilizar o método append:

>>> cidades.append("São José dos Campos")
>>> print(cidades)

Para remover um elemento de uma posição específica de uma lista, utilizamos a operação del junto com o opetrador de índice ([]):

>>> del cidades[1]
>>> print(cidades)
['Belo Horizonte', 'Rio de Janeiro', 'São Paulo', 'São José dos Campos']

Para incluir os elementos de uma lista na outra, pode-se utilizar o método extend:

>>> cidades.extend( ["Ouro Preto", "Mariana"] )
>>> print(cidades)
['Belo Horizonte', 'Rio de Janeiro', 'São Paulo', 'São José dos Campos', 'Ouro Preto', 'Mariana']

Para inverter a ordem dos elementos de uma lista, utilize o método reverse:

>>> cidades.reverse()
>>> print(cidades)
['Mariana', 'Ouro Preto', 'São José dos Campos', 'São Paulo', 'Rio de Janeiro', 'Belo Horizonte']

Nota

Para uma lista completa das operações sobre sequências mutáveis, consulte [28].

2.16.3.1. Construindo Listas

As listas podem ser construídas de diversas formas:

  • Uma lista vazia, por exemplo, pode ser criada da seguinte maneira:

    >>> lista_vazia = []
    >>> print(lista_vazia)
    []
    
  • Uma lista pode ser criada a partir do construtor do tipo list, com uma sequência de valores:

    • Lista vazia:

      >>> list()
      []
      
    • Lista a partir de uma string:

      >>> lista_letras = list("Introdução à Programação")
      >>> print(lista_letras)
      ['I', 'n', 't', 'r', 'o', 'd', 'u', 'ç', 'ã', 'o', ' ', 'à', ' ', 'P', 'r', 'o', 'g', 'r', 'a', 'm', 'a', 'ç', 'ã', 'o']
      
    • Lista a partir de uma tupla:

      >>> primos = list((1, 2, 3, 5, 7))
      >>> print(primos)
      [1, 2, 3, 5, 7]
      
    • Lista a partir de um range (iterável):

      >>> lista_0_ate_9 = list(range(10))
      >>> print(lista_0_ate_9)
      [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      

2.16.3.2. List Comprehension

Uma maneira prática de construir listas é através da notação conhecida como list comprehensions. Esta notação, inspirada na linguagem funcional Haskell, apresenta a seguinte sintaxe básica:

[x for x in iterable]

Exemplos:

  • Lista com os números no intervalo de 0 a 9:

    >>> lista = [ x for x in range(0, 10) ]
    
    >>> print(lista)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    
    >>> type(lista)
    <class 'list'>
    
  • Lista dos quadrados:

    >>> quadrados = [ x**2 for x in range(0, 10) ]
    
    >>> print(quadrados)
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
  • Suponha uma reta definida pela seguinte equação: \(y = 1.5 \times x - 3\). Dado os valores de \(x \in \{ 1, 2, 3, 4, 5 \}\), computar a lista de valores \(y\):

    >>> xs = [ 1, 2, 3, 4, 5 ]
    
    >>> ys = [ (1.5 * x - 3) for x in xs ]
    
    >>> print(ys)
    [-1.5, 0.0, 1.5, 3.0, 4.5]
    

Exemplos

Vamos fazer os exemplos 08 e 09.

2.16.4. Generator Expressions

Outra notação concisa muito usada na linguagem Python é a de generator expressions. Muito parecida com a notação de list comprehensions, a sintaxe básica é a seguinte:

(x for x in iterable)

Diferentemente da notação de list comprehensions, que retorna uma lista, esta notação retorna um iterador ou gerador (generator):

>>> xs = [ 1, 2, 3, 4, 5 ]

>>> ys = ( (1.5 * x - 3) for x in xs )

>>> type(ys)
<class 'generator'>

ys é tratado como um iterador, que gera os valores à medida do necessário:

>>> for y in ys:
...     print(y)
...
-1.5
0.0
1.5
3.0
4.5

Esta estratégia evita que todos os elementos tenham que ser materializados de uma única vez. Repare que a grande diferença na notação é o uso de parênteses (( e )) no lugar de colchetes ([ e ]).

Nota

Para mais detalhes sobre List Comprehension e Generator Expressions, consulte [21] e [48].