A Tuple
is quite similar to a Vector
(1-D array
) in many ways.
However, there are a few important differences.
- Tuples are written in parentheses
( )
instead of brackets[ ]
, though the parentheses can be omitted in cases where the meaning is unambiguous. - Tuples are not required to be homogeneous: the type of each element is stored independently.
- Tuples are immutable.
Immutability allows more compiler optimizations and makes tuples more performant than vectors, so they should be preferred in cases where mutability is not necessary.
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}
For any tuple, it is possible to access elements by index or loop over them.
Any purely numerical tuple can also be used in mathematical functions such as sum()
, exactly like arrays.
A Tuple
contains only values.
A NamedTuple
pairs each value with a name.
Individual fields can then be accessed with "dot" notation:
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
The name is stored internally as a Symbol
(discussed in a later Concept), so there is an alternative syntax available:
julia> nt[:b]
7.3
It is sometimes useful to split creation of a named tuple into two steps:
- Define the fields as as custom data type.
- Use this as a constructor to convert a tuple to a named tuple.
# 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
There are surprisingly many other ways to create a named tuple, so check the documentation if you are interested.
It is easy to get either the names (also called "keys") or values separately:
julia> keys(s)
(:name, :grade)
julia> values(s)
("Helen", 3)
Note that iteration over a named tuple only produces the values, and the names are ignored.
If the names are also useful in an iteration, more steps are needed.
The NamedTuple
can be converted to a Vector
of Pairs
(Pair
s are the subject of another Concept).
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
The named tuple is thus quite dictionary-like.
However, it differs from a [Dict
][dict] in Julia in some important ways:
- A
Dict
is mutable; aNamedTuple
, like any tuple, is immutable. - A
Dict
is flexible in the type of keys it accepts; aNamedTuple
can only use symbols as keys.
Tuples (named or not) are a very common way to transfer structured data to and from functions. Immutability is good in this use case, providing data safety and allowing more aggressive compiler optimizations.