Tu

Tuplas em Julia

1 exercício

Sobre Tuplas

Um Tuple é bastante parecido com um Vector (um array unidimensional) em vários aspectos. No entanto, existem algumas diferenças importantes.

  • As tuplas são escritas entre parênteses ( ) em vez de colchetes [ ], embora os parênteses possam ser omitidos nos casos em que o significado não é ambíguo.
  • As tuplas não precisam 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 que os vetores, então elas devem ser preferidas quando 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}

Também existe um construtor Tuple(), que transforma qualquer coleção iterável em uma tupla. Isso é útil porque ele trata uma string como uma coleção iterável de caracteres.

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

Em qualquer tupla, é possível acessar elementos por índice ou iterar sobre eles.

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

Desempacotamento

Uma tupla pode ser desempacotada em elementos individuais usando atribuição múltipla. Para elementos que não são necessários, use o sublinhado _ como variável descartável.

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, de forma mais geral), existe um operador splat ... que a desempacota. Isso será abordado com mais detalhes no Conceito de 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 acessados 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 é prefixado com dois-pontos :), então há uma sintaxe alternativa disponível:

julia> nt[:b]
7.3

Às vezes é útil dividir a criação de uma tupla nomeada em duas etapas:

  1. Defina os campos como um tipo de dado personalizado.
  2. Use isso como um construtor para converter uma tupla em uma 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

Existem surpreendentemente muitas outras formas de criar uma tupla nomeada, então consulte a documentação se tiver interesse.

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

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

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

Repare 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 em uma iteração, mais etapas serão necessárias. A NamedTuple pode ser convertida em um Vector de Pairs (os Pairs são o assunto 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 é, portanto, bastante parecida com um dicionário. No entanto, ela difere de um [Dict][dict] em Julia em alguns aspectos 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 symbols como chaves.

As tuplas (nomeadas ou não) são uma forma muito comum de transferir dados estruturados de e para funções. A imutabilidade é boa nesse caso de uso, pois oferece segurança dos dados e permite otimizações mais agressivas do compilador.

Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Tuplas