opération | tuple | list | array | string |
---|---|---|---|---|
exemple | let t = (1, true, 3.14) |
let l = [1; 2; 3] |
let a = [|1; 2; 3|] |
let s = "Hello" |
taille | taille connue à la création | utiliser une fonction récursive (ou List.length ) |
Array.length |
String.length |
décomposer | let a, b, c = t |
let e::q = l ou match l with | [] -> ... | e::q -> ... |
impossible | impossible |
obtenir ième élément | décomposer le tuple | fonction récursive | a.(i) |
s.[i] |
modifier élément | impossible | impossible | a.(i) <- ... |
impossible |
ajouter élément | impossible | e::l (renvoie une nouvelle liste) |
impossible | impossible |
mutable | non | non | oui | non |
Tableau¶
Un tableau (array
) se définit avec [|...; ...; ...|]
:
let a = [|1; 2; 3|] (* tableau contenant 1, 2, et 3 *)
val a : int array = [|1; 2; 3|]
Le type est int array
: tableau d'entiers.
On peut accéder à l'élément d'indice i
d'un tableau avec a.(i)
:
a.(0) (* 1er élément de a *)
- : int = 1
Attention : Les indices d'un tableau de taille $n$ vont de 0 à $n - 1$. On obtient une erreur "index out of bounds" si on dépasse :
let a = [|1; 2; 3|] in
a.(4) (* a.(4) n'existe pas *)
Exception: Invalid_argument "index out of bounds".
Raised by primitive operation at unknown location
Called from file "toplevel/toploop.ml", line 208, characters 17-27
On peut modifier un élément avec a.(i) <- ...
:
a.(0) <- 5;
a (* on a bien modifié a *)
- : int array = [|5; 2; 3|]
Un array est donc mutable, contrairement aux listes.
Par contre la taille d'un tableau ne peut pas être modifié, une fois qu'on l'a crée.
Array.length a (* taille de a *)
- : int = 3
Il est possible de créer un tableau de taille arbitraire en écrivant :
Array.make 10 0;; (* crée un tableau contenant 10 fois l'élement 0 *)
- : int array = [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]
Bien sûr, on peut remplir le tableau avec une autre valeur initiale :
Array.make 7 1.23;; (* crée un tableau de 7 éléments contenant 1.23 *)
- : float array = [|1.23; 1.23; 1.23; 1.23; 1.23; 1.23; 1.23|]
Les tableaux sont passés par référence aux fonctions : si une fonction modifie un array
en argument, elle le modifie aussi à l'extérieur de la fonction.
Exemple :
let f a = (* fonction qui met 42 dans la 1ere case du tableau a *)
a.(0) <- 42 in
let t = [|0; -3; 4|] in
f t;
t (* la modification de t à l'intérieur de f a modifié le tableau à l'extérieur *)
- : int array = [|42; -3; 4|]
Exercice
Écrire une fonction pour calculer le maximum d'un tableau d'entiers.
Exercice
Écrire une fonction swap : 'a array -> int -> int -> unit
telle que swap a i j
échange les éléments a.(i)
et a.(j)
.
Matrices¶
Une matrice est un tableau de tableaux, ou, de façon équivalente, un tableau à 2 dimensions (signifiant qu'il faut donner 2 indices pour accéder à un élément). Exemple :
let m = [|[|1; 2|]; [|3; 4|]|]
val m : int array array = [|[|1; 2|]; [|3; 4|]|]
Cette matrice m
correspond à la représentation mathématique suivante :
$$\begin{pmatrix}
1 & 2 \\
3 & 4
\end{pmatrix}$$
On peut sauter des lignes pour plus de clarté :
let m = [|
[|1; 2|]; (* 1ère ligne de la matrice m *)
[|3; 4|] (* 2ème ligne *)
|]
val m : int array array = [|[|1; 2|]; [|3; 4|]|]
On voit d'après la définition de m
que m
est un tableau dont les éléments sont des tableaux. Le premier sous-tableau de m
(c'est-à-dire [|1; 2|]
) correspod à la 1ère ligne, par exemple.
m.(0) (* 2ème ligne de m *)
- : int array = [|1; 2|]
On peut accéder à l'élément sur la ligne i
, colonne j
avec m.(i).(j)
:
m.(1).(0) (* élément sur la ligne 1, colonne 0 de m *)
- : int = 3
Exercice
Comment connaitre le nombre de lignes d'une matrice m
? Et son nombre de colonnes ?
Exercice
Écrire une fonction pour transposer une matrice m
, c'est à dire obtenir tm
telle que tm.(i).(j) = m.(j).(i)
.
On pourra modifier m
en place (sans créer de nouvelle matrice).
Pour créer une matrice, on peut utiliser Array.make_matrix
:
Array.make_matrix 4 3 0 (* crée une matrice de 4 lignes et 3 colonnes remplie de 0 *)
- : int array array = [|[|0; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]|]
Attention On pourrait avoir envie de créer une matrice comme ci-dessous. Pourquoi est-ce en réalité une très mauvaise idée ?
Array.make 4 (Array.make 3 0)
- : int array array = [|[|0; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]; [|0; 0; 0|]|]
Chaîne de caractères (string)¶
Une chaîne de caractères permet de contenir du texte :
let s = "Hello World"
val s : string = "Hello World"
s.[1] (* le caractère à la position 1 *)
- : char = 'e'
Un caractère (char) correspond à un symbole (lettre, chiffre, ponctuation...).
On ne peut pas modifier une string : ni ajouter un caractère ni en modifier un.
s.[0] <- 'a' (* ne marche pas : un string est persistant *)
File "[6]", line 1, characters 0-12: 1 | s.[0] <- 'a' (* ne marche pas : un string est persistant *) ^^^^^^^^^^^^ Alert deprecated: Stdlib.String.set Use Bytes.set instead.
File "[6]", line 1, characters 0-1: 1 | s.[0] <- 'a' (* ne marche pas : un string est persistant *) ^ Error: This expression has type string but an expression was expected of type bytes