CORRECTION DES EXERCICES TYPES Calcul d`une
Transcription
CORRECTION DES EXERCICES TYPES Calcul d`une
COR R ECTION DE S EXER CICE S TYPE S Calcul d'une distribution de probabiltiés Problème : à partir d'une série de valeurs, on veut obtenir le nombre de valeurs par intervalle pour différentes tailles d'intervalle. Fichier : http://rdorat.free.fr/Enseignement/VBA/formationVBA/Exercices/Distribution/Distribution.xls : l'ensemble des valeurs est contenu dans la première colonne de la première page. Solution : Le principe est le suivant : on crée un tableau distribution. Ce tableau associe à indice, distribution(indice) qui est le nombre des valeurs de la colonne 1 qui sont dans [ indice ; indice1[ . Il reste à parcourir la colonne A pour rentrer les valeurs dans le tableau (ETAPE 1) puis à afficher la distribution dans les colonnes B et C (ETAPE 2) Sub distributionValeurs() Dim distribution(1000) As Integer Dim ligne As Integer, indice As Integer 'ETAPE 1 : renseignement de la distribution ligne = 1 While Cells(ligne, 1) <> "" distribution(Int(Cells(ligne, 1))) = distribution(Int(Cells(ligne, 1))) + 1 ligne = ligne + 1 Wend ligne = 1 'ETAPE 2: Affichage For indice = 0 To 1000 If (distribution(indice) > 0) Then Cells(ligne, 2) = "[" & indice & ";" & (indice + 1) & "[" Cells(ligne, 3) = distribution(indice) ligne = ligne + 1 End If Next indice End Sub Une variante : Ici la le tableau distribution associe indice à distribution(indice) qui est le nombre d'élements dans [ indice indice1 ; 10 10 [ , le principe reste le même : Sub distributionValeursGranulariteDifferente() Dim distribution(10000) As Integer Dim ligne As Integer, indice As Integer 'ETAPE 1 ligne = 1 'On parcourt la premiere colonne While Cells(ligne, 1) <> "" indice = Int(Cells(ligne, 1) * 10) distribution(indice) = distribution(indice) + 1 ligne = ligne + 1 Wend 'ETAPE 2 ligne = 1 For indice = 0 To 10000 If (distribution(indice) > 0) Then Cells(ligne, 2) = "[" & (indice / 10) & ";" & (indice + 1) / 10 & "[" Cells(ligne, 3) = distribution(indice) ligne = ligne + 1 End If Next indice End Sub Création d'un générateur aléatoire à partir d'une distribution de probabilités Problème : à partir d'une distribution de probabilités sur des entiers, on veut créer un générateur aléatoire qui respecte cette distribution de probabilité. La distribution de probabilité est donnée sous la forme suivante : Fichier Colonne E Colonne F Ligne 1 0 0.09 Ligne 2 1 0.34 Ligne 3 2 0.07 Ligne 4 3 0.12 Ligne 5 4 0.38 : http://rdorat.free.fr/Enseignement/VBA/formationVBA/Exercices/Distribution/DistributionProba.xls : Solution : Le principe est le suivant, on tire une valeur x entre 0 et 1 avec le générateur aléatoire de VBA. On procède de la sorte : ● si x est dans [ 0 : 0.09 [ alors la valeur générée est 1. Ainsi, la masse de probabilité associée à 1 est 0.09 ● [ 0.09 : 0.43 [ si x est dans alors la valeur générée est 2. Ainsi, la masse de probabilité associée à 2 est 0.43-0.09=0.34 ● [ 0.43 : 0.5 [ si x est dans alors la valeur générée est 3. Ainsi, la masse de probabilité associée à 3 est 0.5-0.43=0.07 ● etc... De manière plus générale, si on veut que l'utilisateur puisse modifier les valeurs dans les cases : ● si x est dans [ 1 0 : ∑ cells i ,6 i=1 [ alors la valeur générée est 1. Ainsi, la masse de probabilité associée à 1 est 0.09 ● si x est dans [ 1 2 i=1 i=1 ∑ cells i ,6: ∑ cells i ,6 [ alors la valeur générée est 2. Ainsi, la masse de [ alors la valeur générée est 3. Ainsi, la masse de probabilité associée à 2 est 0.43-0.09=0.34 ● si x est dans [ 2 3 i=1 i=1 ∑ cells i ,6: ∑ cells i ,6 probabilité associée à 3 est 0.5-0.43=0.07 ● etc... L'implémentation de la fonction de génération aléatoire s'est déduit assez immédiatement, la fonction de tirage aléatoire d'un nombre dentre 0 et 1 est Rnd. Function versionNaive1() As Integer Dim x As Double x = Rnd If Cells(1, 6) > x Then versionNaive1 = 0 ElseIf Cells(1, 6) + Cells(2, 6) > x Then versionNaive1 = 1 ElseIf Cells(1, 6) + Cells(2, 6) + Cells(3, 6) > x Then versionNaive1 = 2 ElseIf Cells(1, 6) + Cells(2, 6) + Cells(3, 6) + Cells(4, 6) > x Then versionNaive1 = 3 Else 'comme x est entre 0 et 1, on est sur que : versionNaive1 = 4 End If End Function Test de la fonction Pour tester la fonction précédente, on peut faire ce type de procédure. Randomize est le mot clé qui permet d'initialiser le générateur aléatoire : il suffit de le faire dans la procédure de plus haut niveau lorsqu'on fait un programme reposant sur de l'aléa. Sub testGenerateurAleatoire() Randomize Dim n(0 To 4) As Double, m As Integer For i = 1 To 5000 m = versionNaive1() n(m) = n(m) + 1 Next MsgBox (n(0) / 5000) MsgBox (n(1) / 5000) MsgBox (n(2) / 5000) MsgBox (n(3) / 5000) MsgBox (n(4) / 5000) End Sub Généralisation Dans le cas général (hors de VBA), la distribution de probabilité sera contenu dans un tableau et non pas dans les cases de la feuille : Function versionGenerale(distrib() As Double) Dim x As Double x = Rnd Dim indice As Integer Dim cumul1 As Double, cumul2 As Double borneBasse = 0 borneHaute = distrib(LBound(distrib)) indice = LBound(distrib) While (x > borneHaute) borneBasse = borneHaute indice = indice + 1 borneHaute = borneHaute + distrib(indice) Wend versionGenerale = indice End Function Publipostage Problème : On dispose d'information, adresses de clients, dans un classeur .xls, on dispose d'un document type au format .doc, on veut créer autant de documents qu'il existe de clients en adaptant chaque fois le document type aux données dont on dispose sur le client. Fichier : Le fichier qui contient les données client : http://rdorat.free.fr/Enseignement/VBA/formationVBA/Exercices/Distribution/DistributionProba.xls : Le document type : http://rdorat.free.fr/Enseignement/VBA/formationVBA/Exercices/tract.doc Solution : On travaille depuis Excel et on crée les documents Word depuis Excel. Avant toute chose, il convient d'activer la librairie objet de Word : Outils-References... On procède en 3 temps. 1- on crée une procédure remplacementOccurrences qui prend en paramètre un objet Word.Application qui est l'application Word courante, une chaine de caractère source et une chaine de caractère chaineModifiee. La procédure a pour effet de modifier chaque occurrence de la chaine source par la chaine chaineModifiee dans le document Word couramment ouvert pour Word.Application. Le code de cette procédure a été obtenue en enregistrant une macro sous Word. Sub remplacementOccurrences(wApp As Word.Application, source As String, chaineModifiee As String) wApp.Selection.Find.ClearFormatting wApp.Selection.Find.Replacement.ClearFormatting With wApp.Selection.Find .Text = source .Replacement.Text = chaineModifiee .Forward = True .Wrap = wdFindContinue .Format = False .MatchCase = False .MatchWholeWord = False .MatchWildcards = False .MatchSoundsLike = False .MatchAllWordForms = False End With wApp.Selection.Find.Execute Replace:=wdReplaceAll End Sub 2- Une procédure qui, à partir d'une ligne de données du document Excel : ● active l'application Word (Etape1), ● ouvre le document type et lance un save as pour crée un nouveau document (Etape2), ● ouvre le nouveau document (Etape 3) ● Procède au remplacement de chaine (Etape 4) ● Sauvegarde, feme le document type, ferme le nouveau document crée, ferme les documents et quitte l'application (Etape 5) Sub publipostage(ligneDonnees As Integer) Dim wApp As Word.Application, doc As Word.Document, newDoc As Word.Document Dim chemin As String 'Etape 1 Set wApp = New Word.Application On Error GoTo quitWord 'Etape 2 chemin = "C:\Data\FormationVBA\Exercices Complets et Cas\Publipostage\" Set doc = wApp.Documents.Open(chemin & "tract.doc") 'On cree un nouveau document identique à tract en sauvegardant doc.SaveAs chemin & "newTract" & ligneDonnees & ".doc" 'Etape 3 'On ouvre le nouveau fichier pour pouvoir le manipuler Set newDoc = wApp.Documents.Open(chemin & "newTract" & ligneDonnees & ".doc") Etape 4 'on procede aux remplacements de chaines en utilisant la fonction précédente Call remplacementOccurrences(wApp, "Civilite", Worksheets(1).Cells(ligneDonnees, 1)) Call remplacementOccurrences(wApp, "NomClient", Worksheets(1).Cells(ligneDonnees, 2)) Call remplacementOccurrences(wApp, "PreClient", Worksheets(1).Cells(ligneDonnees, 3)) Call remplacementOccurrences(wApp, "Adresse1", Worksheets(1).Cells(ligneDonnees, 4)) Call remplacementOccurrences(wApp, "ComplementAdresse", Worksheets(1).Cells(ligneDonnees, 5)) Call remplacementOccurrences(wApp, "CodePostal", Worksheets(1).Cells(ligneDonnees, 6)) Call remplacementOccurrences(wApp, "VilleClient", Worksheets(1).Cells(ligneDonnees, 7)) Call remplacementOccurrences(wApp, "dateJour", Now()) Etape 5 doc.Close newDoc.SaveAs chemin & "newTract" & ligneDonnees & ".doc" newDoc.Close quitWord: wApp.quit End Sub 3- Il ne reste plus qu'à lancer la procédure pour chacune des lignes concernées : Sub launchPublipostage() Dim ligne As Integer For ligne = 6 To 8 publipostage (ligne) Next ligne End Sub Actualisation et calcul de tri Des codes solutions sont disponibles sur : http://rdorat.free.fr/Enseignement/VBA/formationVBA/Exercices/Actualisation/EXC1_Solution.xls Exploration Disque dur Problème : On veut faire différentes algorithme d'exploration du disque dur : comment à partir d'un répertoire obtenir la taille totale de ce répertoire en prenant en compte les sous-repertoire ? Comment calculer la distribution des extensions des fichiers d'un répertoire en prenant là aussi en compte l'ensemble des sous-repertoires ? Solution 1 : Algorithme de calcul de la taille d'un repertoire. Sub testTailleRepertoire() 'le standard : on crée un objet qui référence le système de fichiers et on l'active Dim oFSO As Scripting.FileSystemObject Dim oDrv As Scripting.Drive Set oFSO = New Scripting.FileSystemObject 'recuperation de la taille MsgBox tailleRepertoire("C:\Data\Enseignement\VBA\", oFSO) End Sub Function tailleRepertoire(chemin As String, oFSO As Scripting.FileSystemObject) As Double 'Recuperation du repertoire Dim rep As Folder, fichier As File, rep2 As Folder Set rep = oFSO.GetFolder(chemin) 'Initialisation de la taille du repertoire tailleRepertoire = 0 'Recuperation de la taille des fichiers For Each fichier In rep.Files tailleRepertoire = tailleRepertoire + fichier.Size Next 'Recuperation de la taille des repertoires For Each rep2 In rep.SubFolders tailleRepertoire = tailleRepertoire + tailleRepertoire(rep2.Path, oFSO) Next End Function Solution 2 : Algorithme de détermination de la distribution des extensions à partir d'un répertoire Sub test2() 'le standard : on crée un objet qui référence le système de fichiers et on l'active Dim oFSO As Scripting.FileSystemObject Dim oDrv As Scripting.Drive Set oFSO = New Scripting.FileSystemObject 'recuperation de la distribution Dim nb(0 To 1000) As Integer, extensions(0 To 1000) As String Dim indice As Integer j = distributionSurExtensions("C:\Data\Enseignement\VBA\", oFSO, nb, extensions, indice) For i = 0 To j Cells(i + 1, 1) = extensions(i) Cells(i + 1, 2) = nb(i) Next End Sub Function distributionSurExtensions(chemin As String, _ oFSO As Scripting.FileSystemObject, nb() As Integer, _ extensions() As String, indice As Integer) As Integer 'Recuperation du repertoire Dim rep As Folder, fichier As File, rep2 As Folder Dim i As Integer, st As String, introduction As Integer Set rep = oFSO.GetFolder(chemin) 'Recuperation de la taille des fichiers For Each fichier In rep.Files introduction = -1 For i = 0 To indice st = getExtension(fichier.Name) If extensions(i) = st Then introduction = i End If Next If introduction > -1 Then nb(introduction) = nb(introduction) + 1 Else extensions(indice) = st nb(indice) = 1 indice = indice + 1 End If Next 'Recuperation de la taille des repertoires For Each rep2 In rep.SubFolders indice = distributionSurExtensions(rep2.Path, oFSO, nb, extensions, indice) Next distributionSurExtensions = indice End Function 'renvoie l'extension d'un fichier Function getExtension(fichier As String) As String getExtension = Mid(fichier, Len(fichier) - 2, 3) End FunctionEnd Function