Tu

Tuples en Julia

1 exercice

À propos de Tuples

Un Tuple est tout à fait semblable à un Vector (un array à une dimension) à bien des égards. Il présente toutefois quelques différences importantes.

  • Les tuples s'écrivent entre parenthèses ( ) plutôt qu'entre crochets [ ], même si les parenthèses peuvent être omises lorsque le sens est sans ambiguïté.
  • Les tuples ne sont pas tenus d'être homogènes : le type de chaque élément est stocké indépendamment.
  • Les tuples sont immuables.

L'immuabilité permet davantage d'optimisations du compilateur et rend les tuples plus performants que les vecteurs, il faut donc les préférer lorsque la mutabilité n'est pas nécessaire.

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}

Il existe aussi un constructeur Tuple(), qui transforme n'importe quelle collection itérable en tuple. C'est pratique : il traite une string comme une collection itérable de caractères.

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

Pour tout tuple, il est possible d'accéder aux éléments par leur indice ou de les parcourir en boucle.

Tout tuple purement numérique peut aussi être utilisé dans des fonctions mathématiques comme sum(), exactement comme les tableaux.

Dépaquetage

On peut dépaqueter un tuple en éléments individuels grâce à l'affectation multiple. Pour les éléments dont on n'a pas besoin, on utilise le tiret bas _ comme variable fictive.

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

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

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

Pour copier tous les éléments d'un tuple dans un autre tuple (ou plus généralement dans une collection), il existe un opérateur splat ... qui permet de le dépaqueter. Ce point sera abordé plus en détail dans le concept Fonctions.

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

Tuples nommés

Un Tuple ne contient que des valeurs. Un NamedTuple associe chaque valeur à un nom.

On peut alors accéder aux champs individuellement avec la notation « point » :

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

Le nom est stocké en interne sous forme de Symbol (un type immuable, et le nom est préfixé par deux-points :), donc une syntaxe alternative est disponible :

julia> nt[:b]
7.3

Il est parfois utile de décomposer la création d'un tuple nommé en deux étapes :

  1. Définir les champs sous forme de type de données personnalisé.
  2. L'utiliser comme constructeur pour convertir un tuple en tuple nommé.
# 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

Il existe étonnamment de nombreuses autres façons de créer un tuple nommé, alors consulte la documentation si ça t'intéresse.

Il est facile d'obtenir séparément soit les noms (aussi appelés « clés »), soit les valeurs :

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

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

À noter que l'itération sur un tuple nommé ne produit que les valeurs, et les noms sont ignorés.

Si les noms sont aussi utiles lors de l'itération, il faut davantage d'étapes. On peut convertir le NamedTuple en un Vector de Pairs (les Pair font l'objet d'un autre 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

Le tuple nommé est donc assez proche d'un dictionnaire. Il diffère toutefois d'un [Dict][dict] de Julia sur quelques points importants :

  • Un Dict est mutable ; un NamedTuple, comme tout tuple, est immuable.
  • Un Dict est souple quant au type des clés qu'il accepte ; un NamedTuple ne peut utiliser que des symboles comme clés.

Les tuples (nommés ou non) sont un moyen très courant de transférer des données structurées vers et depuis des fonctions. L'immuabilité est un atout dans ce cas d'usage : elle assure la sécurité des données et permet des optimisations plus agressives du compilateur.

Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet

Apprends Tuples