Accélérer programme Apps Script
Bonjour à tous
J'avais créé un programme VBA sur excel qui me permet d'obtenir le taux de conversion optimal à partir de plusieurs combinaisons de matchs.
J'ai transféré le programme sur Google apps script en utilisant chatGPT mais il est très lent en comparaison avec le programme VBA (env 40s)
J'ai essayé de l'optimiser du mieux que je pouvais mais je ne connais pas assez google apps script pour savoir si il peut être encore amélioré.
Le programme ressemble à ça :
function maximiserTauxConversion() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var wsChoixMatch = ss.getSheetByName("choix match");
var wsFeuilleCalcul = ss.getSheetByName("Feuille de calcul");
if (!wsChoixMatch || !wsFeuilleCalcul) {
SpreadsheetApp.getUi().alert("Une ou plusieurs feuilles de calcul spécifiées sont manquantes.");
return;
}
// Récupérer les données des matchs et du taux de conversion
var matches = wsChoixMatch.getRange("D6:D15").getValues().flat();
var tauxCell = wsFeuilleCalcul.getRange("R29");
if (matches.length < 3) {
SpreadsheetApp.getUi().alert("Il doit y avoir au moins 3 matchs dans la plage spécifiée.");
return;
}
// Initialiser les variables
var tauxMax = -1;
var bestMatches = [];
// Générer toutes les combinaisons de 3 matchs
var combinaisons = getCombinations(matches, 3);
// Parcourir chaque combinaison
for (var i = 0; i < combinaisons.length; i++) {
// Simuler la sélection des matchs dans les cellules L7, L8, et L9
wsChoixMatch.getRange("L7:L9").setValues(combinaisons[i].map(function(match) { return [match]; }));
// Récupérer le taux de conversion actuel
var tauxActuel = tauxCell.getValue();
// Vérifier si tauxActuel est un nombre
if (isNaN(tauxActuel)) {
SpreadsheetApp.getUi().alert("Le taux de conversion actuel n'est pas un nombre valide. Vérifiez la cellule R29.");
return;
}
// Si le taux de conversion actuel est supérieur au maximum, mettre à jour le taux maximum et les matchs correspondants
if (tauxActuel > tauxMax) {
tauxMax = tauxActuel;
bestMatches = combinaisons[i];
}
}
// Après la boucle, afficher la meilleure combinaison dans les cellules L7, L8 et L9
wsChoixMatch.getRange("L7:L9").setValues(bestMatches.map(function(match) { return [match]; }));
}
// Fonction pour générer toutes les combinaisons de k éléments à partir d'un tableau
function getCombinations(arr, k) {
var i, subI, ret = [], sub, next;
for (i = 0; i < arr.length; i++) {
if (k === 1) {
ret.push([arr[i]]);
} else {
sub = getCombinations(arr.slice(i + 1, arr.length), k - 1);
for (subI = 0; subI < sub.length; subI++) {
next = sub[subI];
next.unshift(arr[i]);
ret.push(next);
}
}
}
return ret;
}Si vous avez des pistes pour améliorer ça.
Merci
Bonjour,
En regardant rapidement, je pense que c'est ce bout là le plus lent :
// Générer toutes les combinaisons de 3 matchs
var combinaisons = getCombinations(matches, 3);
// Parcourir chaque combinaison
for (var i = 0; i < combinaisons.length; i++) {
// Simuler la sélection des matchs dans les cellules L7, L8, et L9
wsChoixMatch.getRange("L7:L9").setValues(combinaisons[i].map(function(match) { return [match]; }));
// Récupérer le taux de conversion actuel
var tauxActuel = tauxCell.getValue();
// Vérifier si tauxActuel est un nombre
if (isNaN(tauxActuel)) {
SpreadsheetApp.getUi().alert("Le taux de conversion actuel n'est pas un nombre valide. Vérifiez la cellule R29.");
return;
}Déjà, tu peux sortir ces lignes de la boucle for et les placer avant (car tauxCell n'est pas modifé dans la boucle, il est donc inutile de récupérer cette valeur à chaque fois) :
// Récupérer le taux de conversion actuel
var tauxActuel = tauxCell.getValue();
// Vérifier si tauxActuel est un nombre
if (isNaN(tauxActuel)) {
SpreadsheetApp.getUi().alert("Le taux de conversion actuel n'est pas un nombre valide. Vérifiez la cellule R29.");
return;
}Ensuite, je ne sais pas combien il y a de combinaisons, mais ça fait certainement beaucoup d'exécutions de cette ligne :
// Simuler la sélection des matchs dans les cellules L7, L8, et L9
wsChoixMatch.getRange("L7:L9").setValues(combinaisons[i].map(function(match) { return [match]; }));Je ne sais pas pourquoi tu modifies plein de fois les mêmes cellules mais il est sûrement possible de ne le faire qu'une seule fois après la boucle ... Et comme tu as déjà une ligne qui fait ça après la boucle, je pense que celle de la boucle est complètement inutile (et donc supprimable).
Si tu corriges tout ça, tu devrais passer à <1 seconde de temps d'exécution
A côté de ça, tu as encore ces lignes dans la boucle :
// Si le taux de conversion actuel est supérieur au maximum, mettre à jour le taux maximum et les matchs correspondants
if (tauxActuel > tauxMax) {
tauxMax = tauxActuel;
bestMatches = combinaisons[i];
}Si tauxMax et tauxActuel ne sont pas modifiés par la boucle, ce bout de code est sans intérêt, car soit le if n'est jamais exécuté, soit il est exécuté à chaque fois (et dans ce cas, bestMatches aura la valeur de la dernière combinaison).
Bref, à moins que j'ai regardé ton code un peu vite, toute cette boucle ne sert quasiment à rien
Merci pour ta réponse.
Oui c'est effectivement la partie qui prend du temps
Pour un peu plus détailler mon fichier, j'avais fait en sorte dans mon excel d'intégrer les cotes associées aux issues de 10 matchs de foot dans 3 menus déroulants, pour initialement déterminer le taux de conversion manuellement. En automatisant ça avec VBA je me suis dit que la solution la plus simple était de faire en sorte de tester chaque possibilité sur les 3 menus déroulants pour en conserver le taux le plus haut (donc 1000 possibilités à tester). J'ai fais ça même si c'est vraiment une solution "brute" parce que le taux de conversion dépend d'énormément de cellule, et ça prenait moins d'1s sur Excel.
Concernant tes propositions :
// Récupérer le taux de conversion actuel
var tauxActuel = tauxCell.getValue();
// Vérifier si tauxActuel est un nombre
if (isNaN(tauxActuel)) {
SpreadsheetApp.getUi().alert("Le taux de conversion actuel n'est pas un nombre valide. Vérifiez la cellule R29.");
return;
}tauxCell est la valeur du taux de conversion directement récupéré dans une cellule, il se met donc à jour automatiquement à chaque itération.
// Simuler la sélection des matchs dans les cellules L7, L8, et L9
wsChoixMatch.getRange("L7:L9").setValues(combinaisons[i].map(function(match) { return [match]; }));L7, L8 et L9 sont des menus déroulants. C'est là où sont intégrés les 10 matchs. Comme pour l'excel l'idée est de tester chaque combinaison unique pour conserver la meilleure. J'ai bien conscience que ce n'est pas optimal, mais je n'ai pas trouvé d'autres solutions.
// Si le taux de conversion actuel est supérieur au maximum, mettre à jour le taux maximum et les matchs correspondants
if (tauxActuel > tauxMax) {
tauxMax = tauxActuel;
bestMatches = combinaisons[i];
}Cette partie permet juste de conserver le meilleur taux testé.
tauxCell est la valeur du taux de conversion directement récupéré dans une cellule, il se met donc à jour automatiquement à chaque itération.
Dans ce cas, si tu veux accélérer ton code, il te faut remplacer ce bout de code par un calcul dans Apps Script (sans setValues/getValue) :
// Simuler la sélection des matchs dans les cellules L7, L8, et L9
wsChoixMatch.getRange("L7:L9").setValues(combinaisons[i].map(function(match) { return [match]; }));
// Récupérer le taux de conversion actuel
var tauxActuel = tauxCell.getValue();Parce que chaque setValues ou getValue, c'est une requête au serveur de Google ... Donc s'il y a 1000 combinaisons, c'est 2000 requêtes pour ce bout de code, donc c'est trèèès lent.