Vetores

No Scheme, um vetor é outra estrutura de dados fundamental usada para agrupar valores. Ao contrário das listas, os vetores são coleções de elementos indexados de tamanho fixo, fornecendo acesso aleatório e atualizações mais rápidas. Cada elemento de um vetor pode ser de qualquer tipo, incluindo outro vetor. Os vetores são representados usando # seguido de parênteses. #(1 2 3)

Embora vetores e listas possam parecer semelhantes, eles servem a propósitos diferentes na programação Scheme:

  • As listas são mais comumente usadas para operações recursivas e estruturas dinâmicas, pois a implementação de nós ligados permite manipular eficientemente o início da lista e percorrê-la por decomposição recursiva.

  • Os vetores, por outro lado, são otimizados para cenários em que é necessário acesso aleatório a elementos ou atualizações em índices específicos, tornando-os mais adequados para casos de uso como tabelas de pesquisa, configurações de tamanho fixo ou operações indexadas de desempenho crítico.

Em essência, as listas são a escolha natural para algoritmos recursivos e dados de tamanho dinâmico, enquanto os vetores brilham quando padrões de acesso de tamanho fixo ou indexados são fundamentais.

Vetores Simples

(vector 1 2 3)
  • Cria um vetor de três elementos: 1, 2 e 3.

Resultado: #(1 2 3)

Acessando elementos vetoriais

Os elementos em um vetor são acessados usando o procedimento vector-ref, que recupera o elemento em um índice especificado (começando em 0).

(define my-vector (vector 1 2 3))
(vector-ref my-vector 0) ; Recupera o elemento no índice 0
(vector-ref my-vector 1) ; Recupera o elemento no índice 1

Iteração: Processando cada elemento em um vetor

Pode iterar através de um vetor usando um loop ou recursão. O Scheme fornece vector-length para determinar o tamanho de um vetor. Aqui está um loop simples para imprimir todos os elementos de um vetor:

(define (print-elements vec)
 (let loop ((i 0))
 (if (< i (vector-length vec))
 (begin
 (lumi-message (number->string (vector-ref vec i))) ; Imprime o elemento
 (loop (+ i 1))) ; Processa o próximo índice
 (lumi-message "done")))) ; Fim do loop
  • Caso Base: Se o índice i atingir o comprimento do vetor, pare o loop.
  • Caso recursivo: Imprima o elemento no índice i e aumente i.

Exemplo de uso

(print-elements (vector 1 2 3))

Resultado:

  • "1"
  • "2"
  • "3"

Resultado: “concluído”

Vetores mistos

Os vetores podem incluir elementos de diferentes tipos, incluindo strings, booleanos, números, outros vetores ou até mesmo o resultado de expressões:

(vector 42 "hello" #t (vector 1 2) (+ 3 4))

Isso cria um vetor com:

  • Um número (@LUMI_TOKEN_26@@)
  • Uma string ("hello")
  • Um booleano (@LUMI_TOKEN_28@@)
  • Outro vetor (@LUMI_TOKEN_29@@)
  • O resultado de uma expressão ((+ 3 4), que é avaliada como 7)

Resultado: #(42 "hello" #t #(1 2) 7)

Construindo Vetores

Os vetores são criados usando vector ou usando make-vector para criar um vetor de tamanho fixo com um valor inicial.

(make-vector 5 0)

Cria um vetor de tamanho 5 com todos os elementos inicializados como 0.

Resultado: #(0 0 0 0 0)

Atualizando vetores

O procedimento vector-set! atualiza um elemento em um vetor em um índice especificado.

(define my-vector (vector 1 2 3))
(vector-set! my-vector 1 42) ; Define o segundo elemento como 42
my-vector

Resultado: #(1 42 3)

Verificando vetores

O procedimento vector? verifica se um determinado valor é um vetor.

(vector? (vector 1 2 3)) ; Verifica se #(1 2 3) é um vetor
(vector? 42) ; Verifica se 42 é um vetor

Resultado:

  • (vector? (vector 1 2 3)) retorna #t (verdadeiro)
  • (vector? 42) retorna #f (falso)

Vetores e comportamento de passagem por referência

No Scheme, os vetores são mutáveis e passados por referência. Isso significa que quando passa um vetor para uma função, a função pode modificar diretamente o vetor original. Quaisquer alterações feitas no vetor dentro da função também serão refletidas fora da função. Esse comportamento é útil para partilhar e atualizar dados com eficiência em diversas funções, mas também requer cautela para evitar efeitos colaterais indesejados.

Exemplo: Modificando um vetor em uma função

Aqui está um exemplo que demonstra como os vetores são passados por referência e modificados:

(define (modify-vector vec index new-value)
 (vector-set! vec index new-value)) ; Atualiza o vetor no índice especificado

(define my-vector (vector 10 20 30))
(modify-vector my-vector 1 99) ; Modifica o segundo elemento para 99
my-vector ; O vetor original agora está atualizado

Resultado: #(10 99 30)

Explicação passo a passo

  1. Crie um vetor: my-vector é inicializado com os valores 10, 20 e 30.
  2. Passar para uma função: my-vector é passado para modify-vector junto com o índice e o novo valor a ser atualizado.
  3. Modificar na função: O procedimento vector-set! atualiza o valor no índice especificado diretamente no vetor original.
  4. Refletir alterações: Como os vetores são passados por referência, as alterações feitas na função são refletidas no vetor original.

Implicações da passagem por referência

  • Desempenho: A passagem de vetores por referência é eficiente porque evita a cópia de grandes estruturas.
  • Efeitos colaterais: Tenha cuidado ao partilhar vetores entre funções para evitar modificações não intencionais nos dados compartilhados.

Operações em vetores

O Scheme fornece vários procedimentos integrados para trabalhar com vetores, incluindo:

  • vector-length: Retorna o número de elementos em um vetor.
  • vector->list: Converte um vetor em uma lista.
  • list->vector: Converte uma lista em um vetor.
(vector-length (vector 1 2 3)) ; Retorna 3
(vector->list (vector 1 2 3)) ; Converte o vetor em lista: (1 2 3)
(list->vector (list 1 2 3)) ; Converte a lista em vetor: #(1 2 3)

Resultado:

  • (vector-length (vector 1 2 3)) retorna 3
  • (vector->list (vector 1 2 3)) retorna (1 2 3)
  • (list->vector (list 1 2 3)) retorna #(1 2 3)

Vetores aninhados

Os vetores no Scheme podem conter outros vetores como elementos, criando uma estrutura aninhada.

(define nested-vector (vector (vector 1 2) (vector 3 4) (vector 5)))

Cria um vetor de três elementos, cada um dos quais é um vetor.

Resultado: #(#(1 2) #(3 4) #(5))

Acessando dados aninhados

Para acessar elementos dentro de um vetor aninhado, use vector-ref várias vezes para navegar pela estrutura.

Exemplo: Acessando Elementos

(vector-ref nested-vector 0) ; Recupera o primeiro elemento: #(1 2)
(vector-ref (vector-ref nested-vector 0) 1) ; Recupera o segundo elemento do primeiro vetor: 2

Resumo

  • Vetores em Scheme são estruturas de dados indexadas de tamanho fixo.
  • Use vector para criar um vetor, vector-ref para acessar elementos e vector-set! para atualizar elementos.
  • Procedimentos integrados como vector-length, vector->list e list->vector permitem operações flexíveis.
  • Vetores aninhados permitem estruturas de dados hierárquicas e complexas.