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 ; indice1[
. 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 indice1
;
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