Comme tu me l’as demandé en MP, j’ai réfléchi à ton problème. Voici une solution n’utilisant pas les boucles. C’est moins optimisé qu’une boucle classique, mais le principe est facile à comprendre.
Voici une fonction explorant un tableau pour trouver l’indice de la valeur la plus proche d’une valeur précise :
func chercherIndexValeurProche(valeur:Double, tableau:[Double]) -> Int {
let ecarts = tableau.map {abs($0 - valeur)}
let ecartMinimal = ecarts.min()!
let indice = ecarts.index(of: ecartMinimal)!
return indice
}
Cela fonctionne en créant un nouveau tableau, contenant l’écart entre la valeur recherchée et les valeurs du tableau.
L’opérateur .map permet de créer une copie d’un tableau contenant le résultat d’un calcul. Je l’utilise pour fabriquer un nouveau tableau renfermant la valeur absolue du décalage entre les valeurs du tableau et une valeur donnée.
Exemple j’ai un tableau contenant les valeurs suivantes :
let tableau = [12.0, 15.0, 18.0]
Et une valeur 14.0
let tableau = [12.0, 15.0, 18.0]
let valeur = 14.0
let ecarts = tableau.map {abs($0 - valeur)}
print ("Tableau : ", tableau)
print ("Ecarts : ", ecarts)
Tableau : [12.0, 15.0, 18.0]
Ecarts : [2.0, 1.0, 4.0]
Le décalage le plus faible est 1.0, qui correspond à la valeur 15.
Pour connaître la valeur la plus faible dans un tableau, il faut utiliser l’opérateur min().
let ecartMinimal = ecarts.min()!
Le point d’exclamation te surprend peut-être. C’est dus au fait que l’opérateur .min() retourne une valeur optionnelle. Swift considère que l’opération d’extraction de la valeur minimale d’un tableau peut échouer (par exemple si le tableau est vide). Il retourne donc une valeur de type Double?.
L’opérateur ! transforme l’information optionnelle en une valeur normale. Techniquement parlant c’est une erreur de convertir brutalement l’optionnelle en valeur normale avec un !, sans aucune vérification. Si le tableau est vide, c’est le plantage assurée. Mais bon, tu connais la structure de ton tableau, il ne devrais pas avoir d’erreur.
Une fois la valeur minimale du tableau connu, on peut connaître sa position (son index) avec l’opérateur .index().
let indice = ecarts.index(of: ecartMinimal)!
De la même manière que précédemment, l’opérateur .index() retourne une valeur optionnelle que je convertit en valeur normale, sans précautions à la hussarde.
Exemple d’utilisation :
let tempsGarcon = [0.0, 52.400, 53.000, 53.600, 54.200, 54.800, 55.400]
let tempsFille = [0.0, 62.800, 63.400, 64.000, 64.600, 65.200, 65.900]
let listeNotes = [10.0, 10.0, 9.5, 9, 8.5, 8, 7.5]
let temps = 54.654
let position = chercherIndexValeurProche(valeur: temps, tableau: tempsGarcon)
print ("temps : ", temps)
print ("Position dans le tableau : ", position)
temps : 54.654
Position dans le tableau : 5
Temps : 54.654 Note : 8.0
L’application indique que la valeur la plus proche de 54.654 est à la position 5 du tableau (valeur 54.800).
Pour connaître la note correspondante, il suffit de lire la position 5 du tableau des Notes.
let note = listeNotes[position]
Pour faciliter l’identification des filles et garçons, tu peux utiliser une énumération :
enum TypeEleve {
case garcon
case fille
}
Cela augmente la lisibilité du code.
// Calcul Note d'un élève
func calculNote(temps:Double, typeEleve:TypeEleve) -> Double {
var index = 0
switch typeEleve {
case .garcon:
index = chercherIndexValeurProche(valeur: temps,
tableau: tempsGarcon)
case .fille:
index = chercherIndexValeurProche(valeur: temps,
tableau: tempsFille)
}
let note = listeNotes[index]
return note
}
Mise en pratique :
let temps = 54.654
let sexe = TypeEleve.garcon
let note = calculNote(temps: temps, typeEleve: sexe)
print ("Temps : ", temps, " Note : ", note)
Temps : 54.654 Note : 8.0
Voilà, c’est juste une base de départ. Et une petite introduction aux opérateurs de tableau de Swift, très souples et très puissants. On peut par exemple trier un tableau en une ligne de code, quelque soit son contenu (nombres ou objets complexes). Ou extraire des informations utiles au sein d’une masse d’informations stockées dans des tableaux.
Voici la version « évoluée » de la méthode de recherche, retournant une valeur optionnelle en cas d’erreur.
func chercherIndexValeurProche(valeur:Double, tableau:[Double]) -> Int? {
// Création d'un tableau contenant les écarts de temps
let ecarts = tableau.map {abs($0 - valeur)}
// Recherche du plus petit écart du tableau
if let ecartMinimal = ecarts.min() {
// Recherche de l'index du petit écart
if let indice = ecarts.index(of: ecartMinimal) {
// On retourne l'index de l'écart
return indice
}
}
// Une erreur s'est produite quelque part
// On retourne la valeur nil
return nil
}
C’est celle que j’utiliserais, en ajoutant un système de gestion d’erreur dans le code. Quelque chose comme :
if let position = chercherIndexValeurProche(..) {
// calculs divers
.....
} else {
print (« ERREUR de recherche dans le tableau .. »)
}