Tu

Tuplas em Julia

1 exercício

Sobre Tuplas

Uma Tuple é bastante semelhante a um Vector (um array unidimensional) em muitos aspetos. No entanto, há algumas diferenças importantes.

  • As tuplas escrevem-se entre parênteses ( ) em vez de parênteses retos [ ], embora os parênteses possam ser omitidos quando o significado é inequívoco.
  • As tuplas não têm de ser homogéneas: o tipo de cada elemento é armazenado de forma independente.
  • As tuplas são imutáveis.

A imutabilidade permite mais otimizações do compilador e torna as tuplas mais eficientes do que os vetores, pelo que devem ser preferidas nos casos em que a mutabilidade não é necessária.

julia> t = (3, 5.2, "xyz")
(3, 5.2, "xyz")

# Non-homogeneous:
julia> dump(t)
Tuple{Int64, Float64, String}
  1: Int64 3
  2: Float64 5.2
  3: String "xyz"

julia> t[2]
5.2

# Immutable:
julia> t[2] = 7.3
ERROR: MethodError: no method matching setindex!(::Tuple{Int64, Float64, String}

Existe também um construtor Tuple(), que transforma qualquer coleção iterável numa tupla. Convenientemente, este trata uma string como uma coleção iterável de carateres.

julia> Tuple("Julia")
('J', 'u', 'l', 'i', 'a')

Em qualquer tupla, é possível aceder aos elementos por índice ou percorrê-los com um ciclo.

Qualquer tupla puramente numérica também pode ser usada em funções matemáticas como sum(), tal como acontece com os arrays.

Desempacotamento

Uma tupla pode ser desempacotada em elementos individuais através de atribuição múltipla. Para elementos que não são necessários, utiliza o sublinhado _ como variável fictícia.

julia> tup = (1, "Julia", true)
(1, "Julia", true)

julia> num, name, _ = tup
(1, "Julia", true)

julia> uppercase(name), 2num
("JULIA", 2)

Para copiar todos os elementos de uma tupla para outra tupla (ou para uma coleção em geral), existe um operador splat ... que a desempacota. Isto será abordado com mais detalhe no conceito Funções.

julia> new_tup = (tup..., π, '😊')
(1, "Julia", true, π, '😊')

Tuplas nomeadas

Uma Tuple contém apenas valores. Uma NamedTuple associa cada valor a um nome.

Os campos individuais podem então ser acedidos com a notação de ponto:

julia> nt = (a = 1, b = 7.3)
(a = 1, b = 7.3)

julia> dump(nt)
@NamedTuple{a::Int64, b::Float64}
  a: Int64 1
  b: Float64 7.3

julia> nt.b
7.3

O nome é armazenado internamente como um Symbol (um tipo imutável, e o nome é precedido de dois pontos :), pelo que existe uma sintaxe alternativa disponível:

julia> nt[:b]
7.3

Por vezes, é útil dividir a criação de uma tupla nomeada em dois passos:

  1. Define os campos como um tipo de dados personalizado.
  2. Usa-o como construtor para converter uma tupla numa tupla nomeada.
# Step 1
julia> Student = NamedTuple{(:name, :grade), Tuple{String, Int}}
@NamedTuple{name::String, grade::Int64}

julia> typeof(Student)
DataType

# Step 2
julia> s = Student( ("Helen", 3) )
(name = "Helen", grade = 3)

julia> dump(s)
@NamedTuple{name::String, grade::Int64}
  name: String "Helen"
  grade: Int64 3

Há surpreendentemente muitas outras formas de criar uma tupla nomeada, por isso consulta a documentação se tiveres interesse.

É fácil obter os nomes (também chamados "chaves") ou os valores separadamente:

julia> keys(s)
(:name, :grade)

julia> values(s)
("Helen", 3)

Repara que a iteração sobre uma tupla nomeada produz apenas os valores, e os nomes são ignorados.

Se os nomes também forem úteis numa iteração, são precisos mais passos. A NamedTuple pode ser convertida num Vector de Pairs (os Pair são o tema de outro conceito).

julia> pairs(s)
pairs(::NamedTuple) with 2 entries:
  :name  => "Helen"
  :grade => 3

julia> collect(pairs(s))
2-element Vector{Pair{Symbol, Any}}:
  :name => "Helen"
  :grade => 3

A tupla nomeada é, assim, bastante semelhante a um dicionário. No entanto, difere de um [Dict][dict] em Julia em alguns aspetos importantes:

  • Um Dict é mutável; uma NamedTuple, como qualquer tupla, é imutável.
  • Um Dict é flexível quanto ao tipo de chaves que aceita; uma NamedTuple só pode usar símbolos como chaves.

As tuplas (com ou sem nomes) são uma forma muito comum de transferir dados estruturados de e para funções. A imutabilidade é vantajosa neste caso, pois garante a segurança dos dados e permite otimizações mais agressivas do compilador.

Editar via GitHub A ligação abre numa nova janela ou separador

Aprende Tuplas