Définissez la fonction range: ?from:int -> ?step:int -> int -> int list
avec un argument obligatoire et deux arguments optionnels. On pourra par exemple l'utiliser de la façon suivante:
range 5
renvoie [0; 1; 2; 3; 4]
range ~from:3 5
renvoie [3; 4]
range ~from:2 ~step:2 5
renvoie [2; 4]
.Pour simplifier, on supposera que l'argument step
est toujours un entier strictement positif.
Ajoutez un argument optionnel "sans valeur par défaut" ?truncate:int
qui, s'il est définit tronque la liste produite pour qu'elle ne comporte que n
éléments. Par exemple, range ~from:1 ~step:2 ~truncate:2 5
renvoie [1; 3]
.
Dans la suite de ce TD, on travaille sur des fichiers au format CSV (Comma-Separated Values). Un fichier CSV est un fichier texte dont le contenu représente un tableau. Chaque ligne du fichier correspond à une ligne du tableau. Les différentes valeurs composant une ligne sont séparées par des virgules.
Par exemple, le fichier exemple.csv
dont le contenu est
Identifiant,Partiel,Projet,Final
,0.3,0.3,0.4
ab12345678,12,15,14
cd98765432,10,,9
ef24681357,11,13
correspond au tableau
------------------------------------------
| Identifiant | Partiel | Projet | Final |
------------------------------------------
| | 0.3 | 0.3 | 0.4 |
------------------------------------------
| ab12345678 | 12 | 15 | 14 |
------------------------------------------
| cd98765432 | 10 | | 9 |
------------------------------------------
| ef24681357 | 11 | 13 | |
------------------------------------------
Remarquez que les cases vides peuvent être représentées par l’absence d’une valeur (comme pour la première case de la deuxième ligne) ou tout simplement omises dans le fichier CSV si elle apparaît en fin de ligne (comme la dernière case).
On représente le contenu d’un fichier CSV par la liste de ces lignes. Une ligne est elle-même la liste de ses valeurs (des chaînes de caractères).
type csv_content = string list list
Définissez une fonction input_lines : in_channel -> string list
qui renvoie la liste des lignes du
canal d’entrée passé en paramètre.
Définissez une fonction read_csv : string -> csv_content
qui lit et renvoie le contenu d’un fichier CSV dont le nom est passé en paramètre.
Définissez une fonction join : string -> string list -> string
telle que join sep l
concatène les éléments de l
séparés par le séparateur sep
.
Définissez une fonction write_csv : csv_content -> string -> unit
telle que write_css c name
écrit c
dans le fichier appelé name
sous un format CSV.
Définissez une fonction max_list : int list -> int list -> int list
qui renvoie une liste dont l’élément d’indice i
est le maximum des éléments du même indice dans les listes passées en paramètres. Si une des listes est plus petite que l’autre, on considère que les éléments manquants sont égaux à 0.
Définissez une fonction print_cell : int -> string -> unit
telle que print_cell n str
affiche un espace, la chaîne str
sur n
caractères (on complète par des espaces si nécessaire), un espace et une barre. Par exemple, print_cell 5 "foo"
affiche la chaîne " foo |"
.
Définissez une fonction print_line : int list -> string list -> unit
qui affiche le contenu d’une ligne. La première liste correspond aux tailles des colonnes et la deuxième au contenu des cellules. Par exemple, print_line [5; 3] ["foo"; "bar"]
affiche la chaîne "| foo | bar |"
.
Définissez une fonction print_csv : csv_content -> unit
qui affiche le contenu d’un fichier CSV comme proposé dans l’exemple introductif.
On cherche à analyser des fichiers CSV dans un format particulier.
La première ligne contient des intitulés.
La deuxième ligne contient des coefficients (sauf pour la première cellule)
correspondant à la pondération d’un examen pour le calcul de la moyenne d’une UE.
Les lignes suivantes correspondent à des étudiants composés d’un identifiant
et d’un certain nombre de notes.
On cherche à obtenir le contenu d’un tel fichier comme un enregistrement data
:
type student = {
id : string;
grades : float option list; (* None correspond à ABI *)
}
type data = {
header : string list;
coeff : float list;
students : student list;
}
Définissez une exception Invalid_format
qui sera levée dès que le fichier analysé ne correspond pas aux
spécifications.
Définissez une fonction parse_coeff : string list -> float list
qui prend en paramètre la ligne correspondant aux coefficients et les convertit en flottant.
Définissez une fonction grades_from_strings : string list -> float option list
qui prend en paramètre la liste des notes et les convertit en flottants si possible. Toute note que l’on ne peut convertir en flottant devient la valeur None
.
Définissez une fonction normalize_grade : int -> float option list -> float option list
telle que normalize_grade n l
renvoie la liste l
complétée par des valeurs None
pour qu’elle soit de taille n
. Si la liste a une taille supérieure à n
, on lève une exception Invalid_format
.
Définissez une fonction parse_student : int -> string list -> student
qui prend en paramètres un nombre de notes attendues et une ligne correspondant à un étudiant. Elle renvoie la représentation de l’étudiant associée.
Définissez une fonction parse_csv : csv_content -> data
qui analyse le contenu d’un fichier CSV et en produit la représentation. Le nombre de notes attendues pour les étudiants est déduit du nombre de coefficients sur la deuxième ligne du fichier.
On cherche maintenant à calculer la moyenne des étudiants présents dans un fichier CSV. Il faudra définir une fonction process_file : string -> string -> unit
qui charge le contenu d’un fichier CSV, ajoute une colonne qui contient la moyenne de chaque étudiant, et l’écrit dans un nouveau fichier.
Définissez une fonction moyenne : float list -> float option list -> float
qui prend en paramètres une liste des coefficients et une liste de notes pour renvoyer la moyenne pondérée de ces notes.
Définissez une fonction process_student : float list -> student -> string list
qui prend en paramètres une liste de coefficients et un étudiant. Elle renvoie la ligne correspondant à l’étudiant. On y trouve son identifiant, ses notes (les valeurs None
deviennent "ABI"
) et sa moyenne.
Définissez la fonction process_file
telle que process_file name_in name_out
lit le fichier name_in
et écrit dans le fichier name_out
. Par exemple, le code suivant
let () = process_file "exemple.csv" "moyenne.csv"
let () = print_csv (read_csv "moyenne.csv")
affiche
----------------------------------------------------
| Identifiant | Partiel | Projet | Final | Moyenne |
----------------------------------------------------
| | 0.3 | 0.3 | 0.4 | |
----------------------------------------------------
| ab12345678 | 12. | 15. | 14. | 13.7 |
----------------------------------------------------
| cd98765432 | 10. | ABI | 9. | 6.6 |
----------------------------------------------------
| ef24681357 | 11. | 13. | ABI | 7.2 |
----------------------------------------------------