Pular para conteúdo

Listas

Em Potigol, listas são estruturas de dados fundamentais que permitem armazenar e manipular coleções ordenadas de elementos.

  • São imutáveis por padrão, o que significa que, uma vez criadas, não podem ser alteradas diretamente, garantindo segurança e consistência em operações funcionais.
  • São altamente versáteis, suportando desde operações básicas, como acesso a elementos e verificação de tamanho, até transformações avançadas, como mapeamento, filtragem e redução.
  • Sintaxe intuitiva e alinhada ao paradigma funcional, as listas são uma ferramenta poderosa para lidar com dados de forma eficiente e expressiva.
  • Oferece suporte a listas mutáveis para casos específicos, bem como estruturas multidimensionais, como matrizes e cubos, ampliando ainda mais suas possibilidades de uso.

1. Criação de Listas

  • Lista literal: [2, 4, 6, 8, 10]
  • Adição de elementos: 2 :: [4, 6, 8, 10][2, 4, 6, 8, 10]
  • Lista preenchida: Lista(5, 0)[0, 0, 0, 0, 0]
  • Lista vazia tipada: Lista.vazia[Inteiro][]

2. Operações Básicas

Método/Operação Exemplo Resultado Descrição
.tamanho [2,4,6,8,10].tamanho 5 Retorna o número de elementos
.cabeça [2,4,6,8,10].cabeça 2 Primeiro elemento da lista
.cauda [2,4,6,8,10].cauda [4,6,8,10] Lista sem o primeiro elemento
.último [2,4,6,8,10].último 10 Último elemento da lista
Acesso por índice a[3] 6 (índices começam em 1)

3. Manipulação de Elementos

As listas são imutáveis por padrão, o que significa que qualquer operação de modificação resulta em uma nova lista, mantendo a original inalterada. Isso garante que as estruturas de dados sejam seguras e consistentes.

Seja a = [2, 4, 6, 8, 10]

  • Remoção: a.remova(4)[2, 4, 6, 10] (remove o elemento na posição 4)
  • Inserção: a.insira(3,5)[2, 4, 5, 6, 8, 10] (insere 5 na posição 3)
  • Atualização: a.atualize(3,5)[2, 4, 5, 8, 10] (alterar o valor da posição 3)
  • Verificação: a.contém(6)verdadeiro

Manipulação de Elementos em Listas Imutáveis

Abaixo estão exemplos de como manipular elementos em listas:

Exemplo 1: Atualização de Elementos

Quando você deseja modificar um elemento específico de uma lista, a operação não altera a lista original, mas cria uma nova lista com a modificação aplicada.

var a := [1, 2, 3, 4]
b = a
a := a.atualize(3, 5)  # Atualiza o elemento na posição 3 para o valor 5
escreva a  # [1, 2, 5, 4]
escreva b  # [1, 2, 3, 4] (a lista original permanece inalterada)

Neste exemplo: - a.atualize(3, 5) cria uma nova lista onde o elemento na posição 3 é substituído por 5. - A lista original b permanece inalterada, demonstrando a imutabilidade.

Operador de atribuição [ ] :=

Em Potigol, o conceito de açúcar sintático se refere a uma sintaxe simplificada e mais intuitiva que facilita a escrita e a leitura do código, sem alterar a funcionalidade subjacente. No caso da manipulação de listas, a expressão:

a[3] := 5

é um açúcar sintático para a operação:

a := a.atualize(3, 5)

O que isso significa?

  • a[3] := 5: Essa sintaxe sugere que estamos "atualizando" o valor na posição 3 da lista a para 5. No entanto, como as listas são imutáveis, essa operação não modifica a lista original. Em vez disso, ela cria uma nova lista com o valor atualizado e a atribui à variável a.
  • a := a.atualize(3, 5): Essa é a forma explícita da operação. O método .atualize cria uma nova lista com o valor na posição 3 substituído por 5, e o resultado é atribuído de volta à variável a.

Por que usar açúcar sintático?

  1. Simplicidade: A sintaxe a[3] := 5 é mais curta e intuitiva, especialmente para quem está acostumado com operações de atualização em listas mutáveis.
  2. Legibilidade: O código fica mais claro e fácil de entender, sem perder a semântica funcional.
  3. Consistência: Mantém a imutabilidade das listas, mas oferece uma forma conveniente de "simular" uma atualização.

Exemplo 2: Atualização de Elementos usando [ ] :=

var a := [1, 2, 3, 4]
a[3] := 5  # Açúcar sintático para a := a.atualize(3, 5)
escreva a  # [1, 2, 5, 4]

Neste exemplo: - A expressão a[3] := 5 cria uma nova lista [1, 2, 5, 4] e a atribui à variável a. - A lista original [1, 2, 3, 4] não é modificada, mas deixa de ser referenciada por a.

Exemplo 3: Inserção de Elementos

Para inserir um elemento em uma posição específica, a operação também gera uma nova lista.

var a := [1, 2, 3, 4]
b = a
a := a.insira(2, 10)  # Insere o valor 10 na posição 2
escreva a  # [1, 10, 2, 3, 4]
escreva b  # [1, 2, 3, 4] (a lista original permanece inalterada)

Exemplo 4: Remoção de Elementos

A remoção de um elemento também resulta em uma nova lista, sem afetar a original.

var a := [1, 2, 3, 4]
b = a
a := a.remova(2)  # Remove o elemento na posição 2
escreva a  # [1, 3, 4]
escreva b  # [1, 2, 3, 4] (a lista original permanece inalterada)

Exemplo 5: Concatenação de Listas

A concatenação de listas também cria uma nova lista, sem modificar as originais.

var a := [1, 2, 3]
var b := [4, 5, 6]
c = a + b  # Concatena as listas a e b
escreva c  # [1, 2, 3, 4, 5, 6]
escreva a  # [1, 2, 3] (a lista original permanece inalterada)
escreva b  # [4, 5, 6] (a lista original permanece inalterada)

Essa abordagem funcional torna Potigol uma linguagem robusta para manipulação de dados, especialmente em cenários onde a imutabilidade é essencial.


4. Transformação de Listas

Método Exemplo Resultado Descrição
.inverta [2,4,6,8,10].inverta [10,8,6,4,2] Inverte a ordem
.ordene [2,6,8,10,4].ordene [2,4,6,8,10] Ordenação padrão
.ordene customizado [1,15,2,...].ordene(- _) [40,15,10,2,2,1] Ordenação decrescente usando lambda - _
.junte [2,4,6].junte(", ") "2, 4, 6" Concatena elementos com separador

5. Combinação de Listas

  • Concatenação: [2,4,6] + [8,10][2,4,6,8,10]
  • Divisão: [2,4,6,8,10].descarte(2)[6,8,10] (remove os primeiros 2 elementos)
  • Seleção: [2,4,6,8,10].pegue(2)[2,4] (pega os primeiros 2 elementos)

6. Funções de Alta Ordem

Método Exemplo Resultado Descrição
.selecione [2,4,6,8,10].selecione(n => n mod 4 == 0) [4,8] Filtra elementos que satisfazem a condição
.mapeie [2,4,6,8,10].mapeie(n => n div 2) [1,2,3,4,5] Transforma cada elemento
.injete [2,4,6].injete(0)((a,b) => a + b) 12 Acumula valores (equivalente a reduce)

7. Matrizes e Cubos

  • Matriz 2D: a = [[1,2], [3,4]]
  • Acesso: a[2][1]3
  • Cubo 3D: Cubo.imutável(2,2,2,"-") → Estrutura 2x2x2 preenchida com "-"

8. Listas Mutáveis

  • Criação: a = Lista.mutável(5, 0)[0,0,0,0,0].mutável
  • Modificação: a[3] := 5[0,0,5,0,0]
    (Obs: Potigol prioriza imutabilidade, mas oferece essa opção para casos específicos)

9. Casos Especiais

  • Divisão condicional: [2,2,3,3,3,6,5,6].divida_quando((a,b) => a <> b)[[2,2],[3,3,3],[6],[5],[6]]
  • Ordenação por critério: [[1], [10,10], ...].ordene(_.tamanho) → Ordena listas pelo tamanho

10. Manipulação de Listas de Objetos em Potigol

Em Potigol, listas de objetos são uma forma eficiente de gerenciar coleções de dados complexos, combinando a imutabilidade das listas com a flexibilidade de tipos personalizados. Abaixo está um exemplo prático de como criar, manipular e iterar sobre listas de objetos, utilizando o tipo Pessoa definido pelo usuário:


1. Definição do Tipo Pessoa

Primeiro, definimos a estrutura do objeto Pessoa com atributos e métodos:

tipo Pessoa
  nome: Texto
  email: Texto
  ano_nascimento: Inteiro
  idade() = 2025 - ano_nascimento
  adulto() = idade >= 18
fim
  • Atributos: nome, email, ano_nascimento.
  • Métodos:
  • idade(): Calcula a idade com base no ano atual (2025 no exemplo).
  • adulto(): Retorna verdadeiro se a idade for maior ou igual a 18.

2. Criação da Lista de Objetos

Usamos um loop para...gere para ler dados e gerar a lista de objetos Pessoa:

pessoas = para i de 1 até 5 gere
  nome = leia_texto     #  o nome do terminal
  email = leia_texto    #  o email do terminal
  ano_nascimento = leia_inteiro  #  o ano de nascimento
  Pessoa(nome, email, ano_nascimento)  # Cria um objeto Pessoa
fim
  • para...gere: Gera uma lista com 5 objetos Pessoa.
  • leia_texto/leia_inteiro: Funções para entrada de dados (simuladas ou reais, dependendo do contexto).

3. Iteração e Formatação da Lista

Podemos iterar sobre a lista e exibir os dados formatados:

para p em pessoas faça
  imprima p.nome  formato "%20s"
  imprima p.email formato "%20s"
  escreva p.idade formato "%3d"
fim
  • para...faça: Itera sobre cada objeto p na lista pessoas.
  • formato: Formata os valores para alinhamento:
  • %20s: Alinha o texto em 20 caracteres.
  • %3d: Alinha números inteiros em 3 dígitos.

Saída esperada (exemplo):

             João        joao@email.com         25
            Maria       maria@email.com         30
             José        jose@email.com         42


4. Operações Comuns com Listas de Objetos

Como as listas são imutáveis, qualquer operação retorna uma nova lista. Exemplos:

a) Filtrar Pessoas Adultas
adultos = pessoas.selecione(p => p.adulto)
escreva "Adultos: {adultos.tamanho}"
b) Mapear Emails
emails = pessoas.mapeie(p => p.email)
escreva emails  # ["joao@email.com", "maria@email.com", ...]
c) Atualizar um Objeto na Lista
var pessoas := ...
# Altera a pessoa na posição 1
pessoas[1] := Pessoa("Nome da Pessoa", "oemail@email.com", 2005)
# Atualiza o email da pessoa na posição 2
pessoas[2] := Pessoa(pessoas[2].nome, "novo_email@teste", pessoas[2].ano_nascimento)

Resumo de Características

  • Imutabilidade: Listas são imutáveis por padrão, garantindo segurança em operações funcionais .
  • Flexibilidade: Suporta desde operações básicas até funções avançadas como mapeamento e redução.
  • Sintaxe intuitiva: Palavras-chave em português facilitam o aprendizado .

Sintaxe

[2, 4, 6, 8, 10]                         # lista literal
2 :: [4, 6, 8, 10]                       # [2, 4, 6, 8, 10]
[2, 4, 6, 8, 10].tamanho                 # 5
[2, 4, 6, 8, 10].cabeça                  # 2
[2, 4, 6, 8, 10].cauda                   # [4, 6, 8, 10]
[2, 4, 6, 8, 10].último                  # 10
[2, 4, 6, 8, 10].pegue(2)                # [2, 4]
[2, 4, 6, 8, 10].descarte(2)                # [6, 8, 10]


[2, 4, 6, 8, 10].inverta                      # [10, 8, 6, 4, 2]
[2, 6, 8, 10, 4].ordene                       # [2, 4, 6, 8, 10]
[1, 15, 2, 10, 2, 40].ordene(- _)             # [40, 15, 10, 2, 2, 1]
[[1], [10,10], [3,3],[40]].ordene(_.tamanho)  # [[1], [40], [10, 10], [3, 3]]
[2, 4, 6] + [8, 10]                           # [2, 4, 6, 8, 10]
[2, 4, 6].junte                               # "246"
[2, 4, 6].junte(", ")                         # "2, 4, 6"
[2, 4, 6].junte("[", ", ", "]")               # "[2, 4, 6]"

a = [2, 4, 6, 8, 10]
a[3]                                     # 6
a.posição(6)                             # 3
a.posição(12)                            # 0
a.contém(6)                              # verdadeiro
a.contém(12)                             # falso
a.remova(4)                              # [2, 4, 6, 10]
a.insira(3,5)                            # [2, 4, 5, 6, 8, 10]

Lista.imutável(5, 0)                     # [0, 0, 0, 0, 0]
Lista.vazia[Inteiro]                     # []   - Lista vazia de inteiros

# Matrizes e Cubos
a = [[1, 2], [3, 4]]                     # Matriz 2x2
a[2]                                     # [3, 4]
a[2][1]                                  # 3
b = Matriz.imutável(2, 2, 0)             # b == [[0, 0], [0, 0]]
c = Cubo.imutável(2, 2, 2, "-")          # c == [[["-", "-"],["-", "-"]],[["-", "-"],["-", "-"]]]
c[1][2][1]                               # "-"

# Listas mutáveis
a = Lista.mutável(5, 0)                      # [0, 0, 0, 0, 0].mutável
a[3] := 5                                    # a == [0, 0, 5, 0, 0].mutável

# Funções de alta-ordem
[2, 4, 6, 8, 10].selecione(n => n mod 4 == 0)       # [4, 8]
[2, 4, 6, 8, 10].mapeie(n => n div 2)               # [1, 2, 3, 4, 5]
[2, 4, 6].injete(0)((a, b) => a + b)                # 0 + 2 + 4 + 6 == 12
[2, 4, 6].injete((a, b: Inteiro) => a + b)          # 2 + 4 + 6 == 12
[2, 4, 6, 2, 4].pegue_enquanto(n => n < 6)          # [2, 4]
[2, 4, 6, 2, 4].descarte_enquanto(n => n < 6)       # [6, 2, 4]
[2,2,3,3,3,6,5,6].divida_quando((a, b) => a <> b)   # [[2,2],[3,3,3],[6],[5],[6]]