Accueil
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi Eclipse MS-Office SQL & SGBD Oracle  4D  Business Intelligence

Cours VB.NET

Date de mise à jour : 05/12/2010


V-H. Les 'Tableaux'
V-H-1. Un tableau est un objet de type Array
V-H-2. Fonction avancées sur les tableaux
V-H-3. Exemple courant d'utilisation des tableaux
V-I. Les 'Collections'
V-I-1. Exemple simpliste
V-I-2. Classification des collections
V-I-3. ArrayList
V-I-4. List (Of)
V-I-5. HashTable
V-I-6. Dictionnary (Of)
V-I-7. SortedList SortedList (Of)et SortedSet
V-I-8. Queue
V-I-9. Stack
V-I-10. Les LinkedList (Of)
V-I-11. HashSet (Of)
V-I-12. BitArray
V-I-13. StringCollection
V-I-14. ObservableCollections, SortedSet(Of T)
V-I-15. Généralisation de la notion de collection
V-I-16. Pourquoi le premier élément est-il 0 ou 1 ?
V-I-17. Exemples sur les collections
V-I-18. Lexique anglais=>Français
V-J. Les 'Structures'
V-J-1. Tableau dans une structure
V-J-2. Allons plus loin
V-J-2-a. Les structures sont des types 'valeur'
V-J-2-b. Les structures peuvent contenir plein de choses
V-J-2-c. Portée


V-H. Les 'Tableaux'

C'est un beau tableau, mais en VB, ce n'est pas ça un tableau!!

Les tableaux permettent de regrouper des données de même type.

Les tableaux vous permettent de faire référence à un ensemble de variables par le même nom et d'utiliser un numéro, appelé index ou indice, pour les distinguer.


Comment déclarer un tableau :

Dim Tableau(3) As Integer 
déclare un tableau de 4 entiers

On remarque que, dés la déclaration du tableau, le nombre d'éléments est bien défini et restera toujours le même. Après As on indique le type utilisé dans le tableau.

Dim Tableau(3) As Integer entraîne la création des variables 'Integer' suivante:

Tableau (0)

Tableau (1)

Tableau (2)

Tableau (3)

Contenu du tableau:

0
0
0
0
soit 4 éléments.

Noter que comme c'est un tableau d'entier, juste après la création du tableau les éléments sont initialisés à 0.

warning Le tableau commence toujours par l'indice 0.
Le nombre d'éléments dans le tableau est toujours égale à l'indice de dimension + 1 (ou l'indice du dernier élément+1)
Dim Tableau(3) comporte 4 éléments (éléments d'index 0 à 3).


Si j'exécute Tableau(4)=5, cela plante et me donne le message d'erreur suivant:
L'exception System.IndexOutOfRangeException n'a pas été gérée
"L'index se trouve en dehors des limites du tableau."
En effet l'élément Tableau (4) n'existe pas (Le tableau comporte 4 éléments, éléments d'index 0 à 3); l'index 4 est trop grand.
On fait parfois cette erreur quand on utilise une variable comme index dans une boucle par exemple et qu'on a mal calculé la valeur maximun de l'index de boucle.


Tableau(1)= 12
permet d'affecter le nombre 12 au 2eme élément du tableau.

0
12
0
0

Dim S As Integer
S=Tableau(1)
permet d'affecter à la variable S le 2eme élément du tableau:


Un tableau peut avoir plusieurs dimensions :

Dim T(2,2)     ' 3 X 3 éléments
Pour un tableau à 2 dimensions le premier argument représente les lignes, le second les colonnes.

Voyons pour chaque élément du tableau le numéro de ligne et celui de la colonne: (pas le contenu des éléments ici mais leurs index)

élément:0,0 élément:0,1 élément:0,2
élément:1,0 élément:1,1 élément:1,2
élément:2,0 élément:2,1 élément:2,2
Exemple:

La première ligne comporte les 3 éléments: T(0,0) T(0,1) et T(0,2)

Pour mettre 33 dans l'élément central:

Dim T(2,2) As Integer

T(1,1)=33
voyons le contenu du tableau:

0 0 0
0 33 0
0 0 0

Il est possible de créer des tableaux à 3, 4 ..dimensions:

Exemple:

Dim T(3,1,2) 
crée un tableau de 4X2X3 éléments.

On peut créer des tableaux de tableaux:

Dim T(2),(2)
Il a autant d'élément que le tableau T (2,2) (mais pour l'accès à un élément, ils fonctionnent plus vite).


Il est possible de créer des tableaux avec tous les types de variable (y compris les structures).

Dim Mois(11) As String    'tableau de String de 12 éléments
Notez que dans ce cas (après la ligne Dim )les éléments contiennent Nothing car le tableau contient des String et quand on déclare une String, elle contient Nothing au départ.

On peut initialiser un tableau (Donner une valeur aux éléments):

En effet après déclaration d'un tableau, il contient:

-la valeur 0 si c'est un tableau de numérique.

-Nothing si c'est un tableau de String ou d'Objet.

Dim mois(11) As String 

'mois (1) contient Nothing

mois(0)="Janvier"

mois(1)="Février"

mois(2)="Mars"
On peut aussi l'initialiser lors de sa déclaration :

Dim Mois() As String ={Janvier,Février,Mars}

' Crée un tableau de type String().
Dim winterMonths = {"December", "January", "February"}

' Crée un tableau de type Integer()
Dim numbers = {1, 2, 3, 4, 5}

'Crée un tableau de Double
Dim b = {1, 2, 3.5} 

'Attention création d'un tableau d'OBJECT
Dim d = {1, "123"} 

'Création de tableau à plusieurs dimensions et de tableau de tableau
    Dim e = {{1, 2, 3}, {4, 5, 6}} 'Integer(,)
    Dim f = {({1, 2, 3}), ({4, 5, 6})} 'Integer()() (jagged array)
On remarque ici, que le nombre d'éléments n'est pas indiqué; comme on initialise 3 éléments, le tableau en aura 3.
On peut même se passer d'indiquer le type (à partir du deuxième exemple), le compilateur déduit le type à partir des littéraux. On nomme cela l'inférence de type.
A part quand on utilise Linq, je pense qu'il faut mieux indiquer explicitement le type de variable.


Autre syntaxe:

'Déclaration
Dim t As String()

'On instancie et on initialise
t = New String(1) {"One", "Two"} 
' on affecte au tableau un nouveau tableau de String contenant "One" et "Two"

 
Dim R(,) as Integer ={{0, 1}, {1, 2}, {0, 0}, {2, 3}}
Dans le premier exemple, on fait les choses en deux étapes, on déclare puis on dimensionne (instanciation) et on initialise un tableau 't'. Dans le second exemple, n déclare et on initialise en même temps un tableau à 2 dimensions, remarquez qu'on rentre les éléments 2 à 2.(Equivalent à R(0,0)=0 R(0,1)=1 R(1,0)=1 R(1,1)=2 ..)


Redim permet de redimensionner un tableau (modifier le nombre d'éléments d'un tableau existant), si on ajoute Preserve les anciennes valeurs seront conservées (Array.Resize fait de même, voir plus bas).

warning Attention, on ne peut pas modifier le nombre de dimension, ni le type des données. Un tableau à 2 dimensions de 20 fois 20 string pourra être redimensionné en tableau de 30 fois 30 String, mais pas en tableau d'entiers ou à 3 dimensions.

Dim T(20,20) As String

...

Redim Preserve T(30,30)

Il est possible d'écrire Dim T( , ) As String

Dim T( , ) As String 'Sans donner les dimensions du tableau: il est déclaré mais n'existe pas car T(1,1)="toto" déclenche une erreur. Il faut avant de l'utiliser écrire Redim T(30,30), (sans remettre As String).

Certaines instructions, comme Split (qui découpe une String pour la mettre dans un tableau), redimensionnent elles-même le tableau au nombre d'élément nécessaire.

Dim Nom() as String

Nom=S.Split(Separateur)

Erase efface le tableau et récupère l'espace.

	Erase Tableau 
Erase Tableau (équivalent à tableau= Nothing ).

Clear réinitialise le tableau (remise à 0 d'un tableau de numérique par exemple).

	Array.Clear(t, 2, 3)
Réinitialisation tableau t à partir de l'élément 1 et pour 3 éléments.


Comment parcourir un tableau?

Pour parcourir un à un tous les éléments d'un tableau, on utilise une boucle:

Exemple: créer un tableau de 11 éléments et mettre 0 dans le premier élément, 1 dans le second, 2 dans le troisième...

Dim T(10) As Integer

Dim i As Integer

 

For i = 0 To 10    'Pour i allant de 0 à 10

         T(i)=i

Next i
La variable de boucle i est utilisée pour parcourir le tableau: on utilise l'élément T( i ) donc successivement T(1) puis T(2)...et on affecte i donc 1 puis 2 puis 3..


On peut aussi utiliser For Each:( un tableau hérite de la classe System.Array)

Dim amis() As String = {"pierre", "jean", "jacques", "toto"}

For Each nom As String In amis

    Console.Out.WriteLine(nom)

Next
L'exemple affiche sur la console (menu Affichage->Fenêtre->Sortie) les noms qui sont dans le tableau.

VB alloue de l'espace mémoire pour chaque élément crée. Ne dimensionnez pas un immense tableau si vous avez besoin d'un tableau de 4*4 car cela utilise de la mémoire inutilement.



V-H-1. Un tableau est un objet de type Array

La Classe Array (tableau) a des propriétés et des méthodes que l'on peut utiliser.

Créons 2 tableaux et examinons les principales méthodes.

Dim a(3) As String

Dim b(3) As String

b=a         'Copie le tableau a dans b

b=a.copy    'Est équivalent
warning Attention: il copie les références (l'adresse, l'endroit ou se trouve la variable) et non pas la valeur de cette variable, ce qui fait que si vous modifiez b(3), a(3) sera aussi modifié.
Car lorsque vous assignez une variable tableau à une autre, seul le pointeur (l'adresse en mémoire) est copié. Donc en fait a et b sont le même tableau.


Pour obtenir une copie 'indépendante' dans un nouveau tableau faire :

b=a.clone 
Dans ce cas si vous modifié a(2), b(2) ne sera pas modifié.

Par contre a(1)=b(1) n'affecte que l'élément a(1).


Soit un tableau Mois()

Clear

Array.Clear(Mois,0,2) Efface 2 éléments du tableau Mois à partir de l'élément 0.


Reverse

Array.Reverse(Mois, 1, 3) inverse les 3 éléments à partir de l'élément 1.


Copy

Array.Copy(Mois,1,Mois2,1,20) copie 20 éléments de Mois vers Mois2 à partir du 2eme élément.

Array.ConstrainedCopy fait la même chose mais annule tous si la copie n'est pas effectuée intégralement.

De même: mySourceArray.CopyTo(myTargetArray, 6) copie TOUS les éléments de la source dans la destination à partir d'un index dans la destination.


Sort

Array.sort(Mois) Trie le tableau Mois

Malheureusement cette méthode marche sur des tableaux unidimensionnels uniquement.

Au lieu d'utiliser un tableau à 2 dimensions (sur lequel la méthode 'Sort' ne marche pas, on peut ruser et créer 2 tableaux et surcharger la méthode sort pour trier les 2 tableaux (un servant de clé, le second d'items):

Array.Sort(myKeys, myValues) (Voir un exemple plus bas).


Equals compare 2 tableaux.

Binarysearch recherche un élément dans un tableau trié unidimensionnel.(algorithme de comparaison binaire performant sur tableau trié)

Exemple :

I=Array.BinarySearch(Mois, "Février") 'retourne I=1  se souvenir le premier élément est Mois(0)
BinarySearch effectue une recherche dichotomique: il regarde l'élément du milieu, si l'élément cherché est plus petit, il regarde l'élément du milieu du haut du tableau.....

C'est rapide mais le tableau doit être trié.

S'il trouve un élément il retourne son index.

Si la recherche échoue, il retourne un nombre négatif, si on effectue un Not sur ce nombre retourné, on a l'index où on doit insérer l'élément.


IndexOf

Recherche un objet spécifié dans un tableau unidimensionnel (trié ou non), retourne l'index de la première occurrence.

Dim myIndex As Integer = Array.IndexOf(myArray, myString)
 
Retourne -1 si l'élément n'est pas trouvé.

LastIndexOf fait une recherche à partir de la fin.

Ici la recherche est linéaire: on compare l'élément recherché avec le premier puis le deuxième, puis le troisième élément...C'est long , mais le tableau n'a pas besoin d'être trié.

On a probablement intérêt à trier le tableau et à faire un Binarrysearch (Cela se dit mais je ne l'ai pas vérifié);


Ubound

Retourne le plus grand indice disponible pour la dimension indiquée d'un tableau.

Dim Indice, MonTableau(10, 15, 20)
Indice = UBound(MonTableau, 1) ' Retourne 10. (1 indique la première dimension du tableau)
 
GetUpperBound même fonction.

Indice = MonTableau.GetUpperBound(0) '( 0 pour première dimension!!) Retourne 10.
Lbound existe (plus petit indice) mais est inutile car toujours égal à 0.


Length retourne un entier qui représente le nombre d'éléments total dans le tableau.

Pour un tableau à une dimension Length-1 retourne l'indice du dernier élément.

Cela est souvent utilisé pour parcourir tous les éléments du tableau:

 Dim t(10) As String

 Dim i As Integer

 For i = 0 To t.Length-1

   t(i)=..

 Next t
On remarque que dans un tableau multi dimension Length n'est pas égale à Ubound.

GetLength(x) retourne un entier qui représente le nombre d'éléments dans la dimension x.


GetValue et SetValue permettent de connaître ou de modifier la valeur d'un élément du tableau:

Mois.GetValue(0) est équivalent à Mois(0)

Dans un tableau à 2 dimensions comment modifier l'élément (0,3):

myArray.SetValue("fox", 0, 3)
C'est équivalent à myArray(0,3)="fox"


ArraySegment permet de définir un segment, une plage dans une Array.(framework 2).

Dim myArrSegMid As New ArraySegment(Of String)(myArray, 2, 5) 'ici le segment débute au second élément et contient 5 éléments.
(Si on modifie un élément de myArrSegMid cela modifie myArray car le segment défini une plage du tableau et non un nouveau tableau)

Sur des tableaux, les actions à effectuer sont principalement:

Rechercher un élément.

Trier le tableau.

Insérer un élément.

Enlever un élément.

On a déjà évoqué cela, mais pour étudier le détail de ces algorithmes voir le chapitre 'Travail sur les tableaux et collections'.


Pour les super pro (débutant passe ton chemin), on peut utiliser des méthodes génériques.

Exemple recherche dans un tableau de Short nommé monTab l'élément 2.

index= Array.indexOf (Of Short)(monTab, 2) est hyper plus rapide que

index= Array.indexOf (monTab, 2) car la première version avec généric est directement optimisée pour les Short.

Il est est de même pour Binarysearch et Sort.

Cela est valable pour les types 'valeur' (peu d'intérêts pour les strings par exemple).


V-H-2. Fonction avancées sur les tableaux

Débutant s'abstenir:

La méthode Resize permet de modifier le nombre d'éléments du tableau sans perdre le contenu:
                  
Dim array As T(10)
Dim newSize As Integer=2

Array.Resize(array, newSize)

La méthode Reverse permet d'inverser les éléments d'un tableau.

Dim t(10) As Integer
        t(1) = 2
        Array.Reverse(t)
On peut aussi spécifier l'indice de début et le nombre d'éléments à inverser.

Dim t(10) As Integer
        t(1) = 2
        Array.Reverse(t, 2, 2)

A partir du Framework 2 les Arrays ont donc de nouvelles méthodes:

  • Exists
  • Le tableau contient-il des éléments qui correspondent aux conditions définies par un prédicat?
  • TrueForAll
  • Chaque élément dans le tableau correspond-il aux conditions définies par un prédicat?
  • Find
  • Recherche un élément qui correspond aux conditions définies par le prédicat et retourne la première occurrence.
  • FindLast
  • Idem pour la derniere occurrence.
  • FindAll
  • Récupère tous les éléments qui correspondent aux conditions définies par le prédicat.
  • ConvertAll
  • Chaque élément est passé individuellement à un Converter, et les éléments convertis sont enregistrés dans le nouveau tableau.

La syntaxe est dela forme Array.Find(Tableau, AdresseOf Predicat)

Un Predicat est une Sub qui retourne True si une condition est remplie.

Exemple fournit par Microsoft: On a un tableau contenant le nom d'animaux préhistoriques, le prédicat retourne True si le nom de l'animal se termine par 'saurus'. On veut savoir si la condition est remplie sur la liste au moins une fois (Exists), si tous les éléments remplissent la condition (TrueForAll), quel élément rempli la condition(Find), le premier, le dernier (FindLast), on veut récupérer dans un nouveau tableau tous les éléments qui remplissent la condition.

  Dim dinosaurs() As String = { "Compsognathus", _
            "Amargasaurus",   "Oviraptor",      "Velociraptor", _
            "Deinonychus",    "Dilophosaurus",  "Gallimimus", _
            "Triceratops" }

        Console.WriteLine()
        For Each dinosaur As String In dinosaurs
            Console.WriteLine(dinosaur)
        Next

        Console.WriteLine(vbLf & _
            "Array.Exists(dinosaurs, AddressOf EndsWithSaurus): {0}", _
            Array.Exists(dinosaurs, AddressOf EndsWithSaurus))

        Console.WriteLine(vbLf & _
            "Array.TrueForAll(dinosaurs, AddressOf EndsWithSaurus: {0}", _
            Array.TrueForAll(dinosaurs, AddressOf EndsWithSaurus))

        Console.WriteLine(vbLf & _
            "Array.Find(dinosaurs, AddressOf EndsWithSaurus): {0}", _
            Array.Find(dinosaurs, AddressOf EndsWithSaurus))

        Console.WriteLine(vbLf & _
            "Array.FindLast(dinosaurs, AddressOf EndsWithSaurus): {0}", _
            Array.FindLast(dinosaurs, AddressOf EndsWithSaurus))

        Console.WriteLine(vbLf & _
            "Array.FindAll(dinosaurs, AddressOf EndsWithSaurus):")
        Dim subArray() As String = _
            Array.FindAll(dinosaurs, AddressOf EndsWithSaurus)

        For Each dinosaur As String In subArray
            Console.WriteLine(dinosaur)
        Next
        
    End Sub

    
    Private Shared Function EndsWithSaurus(ByVal s As String) _
        As Boolean
    'Retourne True si la fin du mot se termine par "saurus"
        If (s.Length > 5) AndAlso _
            (s.Substring(s.Length - 6).ToLower() = "saurus") Then
            Return True
        Else
            Return False
        End If
    End Function
Résultat affiché:

'Compsognathus
'Amargasaurus
'Oviraptor
'Velociraptor
'Deinonychus
'Dilophosaurus
'Gallimimus
'Triceratops
'
'Array.Exists(dinosaurs, AddressOf EndsWithSaurus): True
'
'Array.TrueForAll(dinosaurs, AddressOf EndsWithSaurus: False
'
'Array.Find(dinosaurs, AddressOf EndsWithSaurus): Amargasaurus
'
'Array.FindLast(dinosaurs, AddressOf EndsWithSaurus): Dilophosaurus
'
'Array.FindAll(dinosaurs, AddressOf EndsWithSaurus):
'Amargasaurus
'Dilophosaurus

Pour Array.ConvertAll, elle retourne un tableau dont chaque élément qui vient d'un premier tableau a été modifié par une fonction:
Ici on va créer une fonction qui mettre en majuscules.

Private Sub Button1_Click() Handles Button1.Click
        Dim dinosaurs() As String = {"Compsognathus", _
            "Amargasaurus", "Oviraptor", "Velociraptor", _
            "Deinonychus", "Dilophosaurus", "Gallimimus", _
            "Triceratops"}
        Dim dinosaurs2() As String
        
       
        dinosaurs2 = Array.ConvertAll(dinosaurs, New Converter(Of String, String)(AddressOf MettreEnMajuscules))

End Sub

Private Shared Function MettreEnMajuscules(ByVal e As String) _
        As String
        Return e.ToUpper
    End Function

On peut aussi utiliser les expressions lambda multilignes:

Dim nums() As Integer = {1, 2, 3, 4, 5}

    nums = Array.FindAll(nums, Function(n)

                                   Console.WriteLine("testing " & n)
                                   Return n > 2

                               End Function)

ForEach:
Exécute une action spécifiée sur chaque élément du tableau spécifié.
Syntaxe de la forme:
Array.ForEach(MyArray, Action)

Exemple: On a un tableau d'Integer, on veut afficher ces nombres et leurs carrés.
On va créer une sub ShowCarré qui reçoit un Integer et affiche le carré.
Il faut ensuite créer une 'Action', un delegate qui pointe sur la Sub.
Enfin, utiliser Array.ForEach.

Sub Demo
   Dim nums() = {2, 3, 5, 4}
  'Créer un delegate pour la méthode ShowCarré
    Dim action As New Action(Of Integer)(AddressOf ShowCarré)

    Array.ForEach(nums, action)
    
End Sub    
    

    Private Shared Sub ShowCarré(ByVal val As Integer)
        Console.WriteLine("{0:d} Carré = {1:d}", val, val * val)
    End Sub

On peut utilisez une expression lambda, voir le chapitre plus loin.

        'Tableau
        Dim nums() = {2, 3, 5, 4}
       
        'Expression lamda multiligne
        'Pour chaque élément du tableau afficher  'nombre: x'
        Array.ForEach(nums, Sub(n)
                                Console.Write("Nombre: ")
                                Console.WriteLine(n)
                            End Sub)
'ou
'Expression lambda simple: affiche la série de nombre
    Array.ForEach(nums, Sub(n) Console.WriteLine(n))  


V-H-3. Exemple courant d'utilisation des tableaux

Exemple détaillé:

Créer un tableau de 6 éléments, mettre dans chaque élément du tableau le carré de son indice, afficher le contenu du tableau.

Cela montre l'intérêt d'utiliser une boucle pour balayer tous les éléments d'un tableau. Première boucle pour remplir le tableau, seconde boucle pour afficher.(Une boucle For ..Next est ici utilisée, on verra cela plus loin.)


      Dim arr(5) As Integer

      Dim i As Integer

      For i = 0 To arr.GetUpperBound(0)' GetUpperBound(0) retourne 5

         arr(i) = i * i

      Next i

 

     For i = 0 To arr.GetUpperBound(0)

         Console.WriteLine("arr(" & i & ") = " & arr(i))

      Next i
Faire une boucle allant de 0 au dernier élément du tableau (For i=0 to ..)

Dans chaque élément du tableau mettre le carré de son indice (arr(i)=i*i )

Nouvelle boucle pour afficher les noms des différents éléments et leur contenu. (Console.WriteLine() affiche sur la console le nom de l'élément et son contenu)

Le programme génère la sortie suivante :

arr(0) = 0

arr(1) = 1

arr(2) = 4

arr(3) = 9

arr(4) = 16

arr(5) = 25
Exemple de recherche dans un tableau:

Dans un tableau de String rechercher dans quel élément et à quelle position se trouve la string "MN".

Dim Tableau() As String = {"ABCDEFG", "HIJKLMNOP"}
Dim AChercher As String = "MN"
Dim i As Integer
Dim position As Integer
For i = 0 To Tableau.Length - 1 'on parcourt chaque élément du tableau
    position = Tableau(i).IndexOf(AChercher) 'dans l'élément  du tableau on cherche la sous-chaîne
    If position >= 0 Then Exit For
Next i
Exemple de tri de 2 tableaux:

On crée un tableau de clés et un tableau des valeurs, à chaque clé est liée une valeur.

On trie à partir du tableau des clés myKeys , le tableau myValues est modifié pour 'suivre' le tri des clés. La Sub PrintKeysAndValues affiche les résultats.

Public Shared Sub Main()

' ****************Création des tableaux.
'Tableau des clé
Dim myKeys() As String = {"red", "GREEN", "YELLOW", "BLUE", "purple", "black", "orange"} 
'tableau des éléments
Dim myValues() As String = {"strawberries", "PEARS", "LIMES", "BERRIES", "grapes", "olives", "cantaloup"} 

 

'Affichage du tableau non trié

Console.WriteLine("Tableau non trié:")

PrintKeysAndValues(myKeys, myValues)


' Tri les éléments 1 à 3 puis affichage.

Array.Sort(myKeys, myValues, 1, 3)

Console.WriteLine("Après tri d'une partie du tableau:")

PrintKeysAndValues(myKeys, myValues)


    ' Tri la totalité du tableau.

Array.Sort(myKeys, myValues)

Console.WriteLine("Après tri de la totalité du tableau:")

PrintKeysAndValues(myKeys, myValues)

End Sub 'Fin de Main

 

    ' Routine affichant dans la console les clés et valeurs

Public Shared Sub PrintKeysAndValues(ByVal myKeys() As [String], ByVal myValues() As [String])

Dim i As Integer

For i = 0 To myKeys.Length - 1

    Console.WriteLine(" {0,-10}: {1}", myKeys(i), myValues(i))

Next i

Console.WriteLine()

End Sub 'PrintKeysAndValues
Création de tableau avec CreatInstance.

' Créons un tableau d'entier (Int32) comprenant 5 éléments.
Dim myArray As Array = Array.CreateInstance(GetType(Int32), 5)
Dim i As Integer
For i = myArray.GetLowerBound(0) To myArray.GetUpperBound(0)
    myArray.SetValue(i + 1, i)
Next i 
Merci Microsoft pour les exemples.


V-I. Les 'Collections'

Une alternative aux tableaux est l'usage de Collection.

Les Collections permettent de regrouper des données. Les collections sont très utilisées dans la programmation 'Objet'.

Une collection fonctionne plutôt comme un groupe d'éléments dans laquelle il est possible d'ajouter ou d'enlever un élément à n'importe quel endroit sans avoir à se préoccuper de la taille de la collection, ni ou se trouve l'élément.

Le nombre d'élément n'est pas défini au départ comme dans un tableau. Dans une collection, il n'y a aucun élément au départ, puis il n'y a que les éléments que l'on a ajouté.

Les éléments sont repérés grâce à un index ou avec une Clé unique

Les items affichés dans une ListBox donnent une idée concrète de ce qu'est une collection.


V-I-1. Exemple simpliste

Soit la collection Col, au départ elle est vide.

J'ajoute des éléments (ou items) à cette collection.

Col.Add ("Toto")

Voici la collection:

Toto
La collection a maintenant 1 élément (On dit un Item).


Je fais maintenant:

Col.Add("Lulu")

Col.Add("Titi")

Toto
Lulu
Titi
La collection a 3 éléments maintenant, l'élément (on dit Item) 0, 1, 2.


Je fais :

Col.Remove(1) enlève le deuxième élément. (Attention on compte les éléments à partir de l'élément 0).

Toto
Titi
La collection n'a plus que 2 éléments maintenant.

On voit que le nombre d'éléments n'est pas connu à l'avance, il varie en fonction des éléments ajoutés (ou retirés)

Un élément est repéré par son indice.

Col.Item(1) contient "Titi" (le second Item de la collection)

Remarque:

J'ai pris une collection de 'Base 0': le premier élément à l'indice 0, c'est habituel dans les classes du Framework; il existe aussi des collections (celles venant de Visual Basic) de Base 1.


V-I-2. Classification des collections

Il est intéressant de classer les collections par fonction:

Il y a les List, comme dans l'exemple simpliste. On a un Index pour repérer les éléments.(Pas de clé).

Toto
Lulu
Titi

Il y a les Dictionnaires, chaque élément à une clé, on parle de Collection Clé-Valeur. On utilise la clé pour retrouvé une valeur.

Certaines collections combinent List et Dictionnaire, d'autres sont triées automatiquement.

Enfin il y a des collections particulières: les Piles, Queue, HashSet, SortedSet....


Certaines collections peuvent contenir des objets, d'autres des Strings ou des Bytes..

Certaines collections utilisent, elles, les génériques: Elles sont faites pour contenir des génériques c'est à dire ce que l'on veut. Quand on utilise la Collection, on indique le type.

Du coup la collection est fortement typée: elle ne peut contenir qu'un type de donnée.

Exemple : List(Of String) est une List ne pouvant contenir que des Strings.


Voici les principales collections:

  • Les Listes:ArrayList, List(Of..) VB 2005
  • Les Dictionnaires:HashTable, Dictionnary
  • Les Listes-Dictionnaires:SortedList,DictionnaryList
  • Les Queue et les Queue (Of..)
  • Les Piles: Les Stack et les Stack (Of..)
  • Les Listes chaînées Les LinkedList(Of....) VB 2005
  • Gestion des ensembles: Les HashSet VB 2008
  • Collections travaillant sur les Bits:BitArray, BitVector32
  • Collections triée: SortedList, SortedDictionnary SortedSet du framework 4
  • Autres: ObservableCollection

V-I-3. ArrayList

Fait partie de System.Collections. c'est une Classe .Net. Il faut donc ajouter en haut du module:

Imports System.Collections
C'est une 'Liste' d'objets, d'Item: La ArrayList est une collection particulière: On peut y mettre des objets : chaînes, nombres... rien n'empêche que le premier élément soit un entier, le second une chaîne… . Il n'y a pas de clé.

warning Attention le premier élément, le premier Item, est ici l'élément 0 (l'index va de 0 à count-1) ; c'est du .NET!!
Exemple:

Dim L As New ArrayList()     'On crée une collection ArrayList

Dim L As ArrayList = ArrayList.Repeat("A", 5) 

'On crée une ArrayList de 5 éléments contenant chacun  "A" (on répète "A")
 

L.Add("Bonjour")             'On ajoute un élément à la collection

MsgBox(L(0))                 'On affiche le premier élément
L.Add() permet d'ajouter un élément; on affiche le premier élément L(0)

On pourra aussi écrire L.Item(0) pour pointer le premier élément, en effet les éléments sont L.Item(0), L.Item(1), L.Item(2)...

MsgBox(L.Count.ToString)     'On affiche le nombre d'élément.
warning Attention c'est le nombre d'éléments. S'il y a 3 éléments dans la ArrayList ce sont les éléments d'index 0,1,2.

L.Remove("Bonjour")          'On enlève l'élément de la liste qui contient "Bonjour"

L.RemoveAt(0)                'On enlève l'élément 0 de la liste

L.Sort()                     'Trie la collection

L.Clear()                    'Efface tous les éléments

L.Contains (élément)        ' Retourne True si la liste contient élément.   
Insert permet d'insérer à un index spécifié:

L.Insert( position, Ainserrer)
InsertRange insère une ArrayList dans une autre ArrayList.


L.Containts (élément)  ' Retourne True si la liste contient 'élément'.

Recherche d'un élément dans une collection NON TRIEE avec IndexOf:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

i = l.IndexOf("lulu")

MsgBox(i.ToString)    'Affiche 1 qui est l'index de "lulu"
On rappelle qu'il existe aussi LastIndexOf qui démarre par la fin et une surcharge permettant de débuter la recherche à partir d'un indice donné. Comment rechercher "lulu" à partir du 3ème élément).

i = l.IndexOf(3,"lulu")

Recherche d'un élément dans une collection TRIEE avec BinarySearch:

Dim l As New ArrayList

Dim i As Integer

l.Add("toto")

l.Add("lulu")

l.Sort()'Il est nécessaire que le tableau soit trié 

i = l.BinarySearch("lulu")

MsgBox(i.ToString) 'affiche 1

Pour parcourir une collection, 3 méthodes :

-Avec l'index de l'item

For i=0 to L.Count-1

      A=L.Item(i)

Next i
NB: Comme vu plus haut, on utilise Count pour trouver le nombre d'élément, aussi la boucle doit balayer de 0 à count-1. Enfin bien se souvenir que A est un Objet, il faudra le convertir pour l'utiliser:

Dim s As String= CType(A,String)

-Avec For Each

Dim o As Objet

For Each o in L

      A=o

Next
Attention, A est un objet. De plus on verra que dans une boucle For Each, on ne peut pas modifier la collection.


-Avec l'objet IEnumerator (débutant passe ton chemin)

On crée un objet C de type IEnumerator pour parcourir la collection, cet objet a 3 propriétés:

MoveNext qui avance d'un élément dans la collection. S'il ne peut plus avancer (s'il est déjà après le dernier) il retourne False

Reset qui place l'élément courant au début, avant le premier élément (Comme au départ)

Current désigne l'élément courant.

Exemple montrant la seule manière de faire pour parcourir la collection:

Dim L As New ListArray

Dim C As IEnumerator= L.GetEnumerator()

While C.MoveNext())

     A=C.Current

End While
warning Attention, si Option Explicit=On
Les éléments de la ListArray étant des objets, on ne peut pas les affecter à une variable String par exemple, il faut écrire:

Str = CType(L(0), String)    'on convertit (on cast) l'objet en String.
Remarque:

L.Add(Nothing)    'est accepté: on ajoute un élément vide

V-I-4. List (Of)

A partir de 2005 on a des collections que l'on peut typer, c'est à dire qu'elles ne pourront contenir qu'un type de donnée, que des String, des entiers, des instances de telle classe... On parle de collections génériques. Le terme Of permet de définir le type de la collection.

Nécessite:

Imports System.Collections.Generic
Créons une liste ne contenant que des 'Decimal'.

Dim lst As New List (Of Decimal) 

Exemple: créons une collection de String List(Of String): Elle est typée car elle ne peut contenir que des 'String'.

Dim lst As New List(Of String)
Il s'agit d'une List avec Index.

lst(0) est le premier élément.

ou lst.item(0)

On ajoute une String:

lst.Add("toto")   
Elle devient le dernier élément de la liste.

Comment affecter cet élément à une String?

Dim S As String = lst.Item(0)  
L'item est bien typé : même avec 'Option Strict=on' pas besoin de CType.


Nombre d'éléments de la list:

lst.Count

On peut à partir de vb 2010 'remplir' simplement une collection grâce à 'From':

 Dim names As New List(Of String) From {"Christa", "Brian", "Tim"}
Noter bien le New.

On peut aussi remplir avec un tableau ou ajouter une List par un AddRange:

Dim input() As String = { "Brachiosaurus", _
                                  "Amargasaurus", _
                                  "Mamenchisaurus" }

Dim Animals As New List(Of String)(input)

'Ajouter une list à une autre liste avec AddRange
Animals.AddRange(2, Animals)

La liste contient t-elle "toto"?

Dim present As Boolean =lst.Contains("toto")
Present = True si la liste contient "toto".


Insérer un élément à une position donnée:

lst.Insert(2, "lulu") 
Supprimer un élément à une position donnée:

lst.Remove("lulu")    'supprime le premier élément contenant "lulu"
lst.RemoveAt(3)       'supprime le 4ème élément
lst.RemoveRange(3,2)  'supprime du 4ème élément au 5ème élément

Parcourir tous les éléments et les afficher:

For Each element As String In lst 

    Console.WriteLine(element) 

Next

Rechercher un élément dans la liste:

lst.IndexOf("lulu") 'retourne l'index de l'élément qui contient "lulu" 

lst.IndexOf("lulu", 2,7) recherche à partir de l'élément 2 et sur 7 éléments.
Il existe aussi LastIndexOf.


Sur une list triée on utilise BinaryScearch, voir ArrayList, c'est parreil.


On peut copier une List ou partie de List dans un tableau:

'Avec CopyTo
Dim array(14) As String 'tableau
lst.CopyTo(array)       'copier la list dans le tableau
lst.CopyTo(array, 6)    'copier 6 éléments de la list dans le tableau
lst.CopyTo(2, array, 12, 3)  'index de départ dans list, tableau, index de départ dans array, nombre

'Avec GetRange
Dim output() As String = lst.GetRange(2, 3).ToArray()

On voit que List (Of) possède toutes les méthodes des ArrayList, mais en plus il existe des méthodes propres aux collections génériques (à partir du Framework 2):

  • Exists
  • List contient-il des éléments qui correspondent aux conditions définies par un prédicat?
  • TrueForAll
  • Chaque élément dans List correspond-il aux conditions définies par un prédicat?
  • Find
  • Recherche un élément qui correspond aux conditions définies par le prédicat et retourne la première occurrence.
  • FindLast
  • Idem pour la dernière occurrence.
  • FindAll
  • Récupère tous les éléments qui correspondent aux conditions définies par le prédicat.
  • ConvertAll
  • Chaque élément est passé individuellement à un Converter, et les éléments convertis sont enregistrés dans la nouvelle collection.
  • RemoveAll
  • Efface les éléments qui correspondent au Predicat
La syntaxe est dela forme ListeResultat= List.Find(Liste, AdresseOf Predicat)

Un Predicat est une Fonction qui retourne True si une condition est remplie.

Exemple:

Exemple 1:
Avec FindAll:
J'ai une list 'Animals', je veux mettre dans 'listResult' tous les éléments de Animals qui se terminent par 'us'.

On crée une liste (listResult) qui grâce à FindAll se chargera des éléments de Animals qui répondent à une condition:

'List de String contenant des noms d'animeaux
Dim Animals As New List(Of String) From {"Compsognathus", _
            "Amargasaurus", "Oviraptor", "Velociraptor", _
            "Deinonychus", "Dilophosaurus", "Gallimimus", _
            "Triceratops"}
            
Dim listResult As List(Of String) = Animals.FindAll(AddressOf SeTermineParUS) 
En argument de FindAll on a l'adresse d'une fonction: ici la fonction 'SeTermineParUS'. Pour chaque élément de Animals si SeTermineParUS retourne True, l'élément correspondant est passé dans listResult.

Voici la fonction de test, le Predicat.

Private Shared Function SeTermineParUS (ByVal s As String) As Boolean 

If (s.Length > 2) AndAlso  (s.Substring(s.Length - 2).ToLower() = "lu") Then
     Return True 
Else 
    Return False 
End If 

End Function

Exemple 2:
Avec ConvertAll on obtient à partir d'une première liste, une seconde liste ou chaque élément à été convertit par une fonction.
Ici on a une liste d'animaux , on va obtenir une seconde liste avec des noms court (4 caractères).

'List de String contenant des noms d'animeaux
Dim Animals As New List(Of String) From {"Compsognathus", _
            "Amargasaurus", "Oviraptor", "Velociraptor", _
            "Deinonychus", "Dilophosaurus", "Gallimimus", _
            "Triceratops"}
'Seconde list de String
Dim Animals2 As New List(Of String)

'Remplir Animals2 avec tous les éléments de Animals après passage par le converteur RaccourcirNom

Animals2 = Animals.ConvertAll(New Converter(Of String, String)(AddressOf RaccourcirNom))


        'Afficher la seconde list
        For Each dinosaur As String In Animals2
            Console.WriteLine(dinosaur)
        Next

   'Fonction  RaccourcirNom  
    Private Shared Function RaccourcirNom(ByVal x As String) As String
       Return x.Substring(0, 4)
    End Function

Trier une List:

Soit une liste (Of String) de noms d'animaux, on veut trier par ordre alphabétique:
On utilise Sort.

Dim Animals As New List(Of String) From {"Compsognathus", _
            "Amargasaurus", "Oviraptor", "Velociraptor", _
            "Deinonychus", "Dilophosaurus", "Gallimimus", _
            "Triceratops"}

        

        Animals.Sort()

Mais on peut indiquer une Fonction qui va definir la manière de trier: Ici je veux trier en fonction de la longueur des String:
Je vais indiquer l'adresse de ma fonction de comparaison comme argument de Sort:

 Dim Animals As New List(Of String) From {"Compsognathus", _
            "Amargasaurus", "Oviraptor", "Velociraptor", _
            "Deinonychus", "Dilophosaurus", "Gallimimus", _
            "Triceratops"}

        

        Animals.Sort(AddressOf CompareByLength)


'Avec la fonction:
 Private Shared Function CompareByLength( _
           ByVal x As String, ByVal y As String) As Integer
                   Return x.Length.CompareTo(y.Length)
End Function


V-I-5. HashTable

C'est un 'Dictionnaire' qui comporte des couples clé-élément, des paires clé-valeur.

Ces couples sont de type Objet-Objet.

La clé toujours unique permet de retrouver la valeur, La clé ne doit pas être vide non plus.


Créons une Hashtable:

Dim H As New Hashtable
H.Add(Clé,Valeur) Ajoute un élément

H.Item(Clé) Retourne l'élément correspondant à une clé.

H.ContainsKey(Clé) Retourne True si la Clé est dans la table.

H.ContainsValues(Valeur) Retourne True si la valeur est dans la table.

H.Clear Efface tous les éléments

H.Remove(Clé) Supprime l'élément ayant une clé spécifiée.

Les collections H.Values et H.Keys contiennent les valeurs et les clés.


Exemple:

'  Creation d'une Hashtable.
Dim myHT As New Hashtable()

' Mettre des éléments dans la HashTable
myHT.Add("un", "premier")
myHT.Add("deux", "second")
myHT.Add("trois", "troisième")
myHT.Add("quatre", "quatrième")
 

'Recherche la valeur correspondant à la clé "trois"

myReponse=myHT.Item("trois")     'Retourne "troisième"
 

'Parcourir la HashTable

'Création d'un IDictionaryEnumerator
Dim myEnumerator As IDictionaryEnumerator = myHT.GetEnumerator()

While myEnumerator.MoveNext()

'Afficher clé et valeur
    MsgBox( myEnumerator.Key+ myEnumerator.Value)
End While

Attention on n'utilise pas de numéro d'index mais uniquement la clé.

En interne, pour chaque élément, la clé est 'hachée' pour créer un code de hashage qui sert à pointer l'élément et sa valeur (voir le chapitre sur l'algorithme), ce procédé accélère la recherche de la valeur à partir de la clé.


V-I-6. Dictionnary (Of)

A partir de VB 2005, il y a cette collection de type Dictionnaire (Clé-Valeur) mais elle utilise les génériques.

La clé doit être unique (pas de doublon de clé).

La récupération d'une valeur à partir de sa clé est très rapide.(Utilisation d'un hachage)

Of permet de choisir le type de la clé et celui des valeurs.

Créons un Dictionnary avec des clés de type String et des valeurs de type String.

Dim Dic As New Dictionary(Of String, String) 

' Ajout d'élément

    Dic.Add("txt", "notepad.exe") 

     Dic.Add("bmp", "paint.exe")

Depuis vb 2010 on peut ajouter rapidement des éléments:

Dim days = New Dictionary(Of Integer, String) From
    {{0, "Sunday"}, {1, "Monday"}}

' Ajout d'élément en vérifiant avant si la clé n'existe pas

  If Not Dic.ContainsKey("ht") Then

         Dic.Add("ht", "hypertrm.exe")

    End If 

' Modifier la valeur correspondant à la clé 'doc'

Dic("doc") = "winword.exe"

'Parcours du Dictionary (le type de clé/Value est KeyValuePair).

For Each kvp As KeyValuePair(Of String, String) In Dic

     Console.WriteLine("Key = {0}, Value = {1}",  kvp.Key, kvp.Value) 

Next kvp

' Récupérer une valeur correspondant à une clé

Dim tt As String = Dic("rtf")

'TryGetValue permet de rechercher une valeur correspondant à une clé, retourne False si la clé n'existe pas (sans déclencher d'erreur).

Dim value As String = "" 

If Dic.TryGetValue("tif", value) Then

     Console.WriteLine("For key = ""tif"", value = {0}.", value)

 Else

     Console.WriteLine("Key = ""tif"" non trouvée.") 

End If

Dic..ContainsKey("ht") permet aussi de tester si une clé existe.

'Enlever un élément

Dic.Remove("doc")


V-I-7. SortedList SortedList (Of)et SortedSet

SortedList:
Combine List et Dictionnaire avec un tri automatique.

Il permet l'accès aux valeurs par l'intermédiaire des clés associées ou des index.

C'est un hybride de HashTable et de Array.

On ajoute un élément par mySL.Add(Clé,Valeur)

La séquence d'index est basée sur la séquence de tri. Quand un élément est ajouté, il est inséré dans l'ordre de tri adéquat, et l'indexation s'ajuste en conséquence. Le tri est donc automatique.

On peut donc lire une valeur par sa Clé ou son Index:
  • Quand la clé d'un élément permet d'accéder à celui-ci à l'aide de la propriété d'indexeur Item, l'élément se comporte comme Hashtable.
    
    mySL.Item(CLE) 'retourne la valeur correspondant à la clé CLE
    
  • Quand l'index d'un élément permet d'accéder à celui-ci à l'aide de GetByIndex ou de SetByIndex, l'élément se comporte comme Array (tableau avec un Index).
    
    mySL.GetKey(3) 'retourne la Clé qui est dans l'élément d'index 3
    
    mySL.GetByIndex(3) 'retourne la valeur qui est dans l'élément d'index 3
    
SortedList maintient en interne deux tableaux , un tableau pour les clés et un autre pour les valeurs associées.

Index de base 0: Le premier élément est 0.

Exemple:

Dim mySL As New SortedList()
mySL.Add("1", "Hello")
mySL.Add("2", "World")
mySL.Add("3", "!")


Console.WriteLine(" Count: {0}", mySL.Count)    'Nombre d'éléments
Console.WriteLine(" Capacity: {0}", mySL.Capacity) 
'nombre d'éléments possible,automatique, on n'a pas à s'en occuper.
 

Dim i As Integer
For i = 0 To mySl.Count - 1
    Console.WriteLine( myList.GetKey(i)& myList.GetByIndex(i)) 
     'affiche les éléments de la collection
     ' par index croissant.
Next i

Les SortedList(Of..) sont des SortedList génériques avec Clé et valeur ,triées sur la clé. Ressemble à SortedDictionary, mais occupe moins de mémoire et est moins rapide pour les insertions/suppressions.

Les SortedDictionnary(Of..) sont des collections génériques avec Clé et valeur ,trié sur la clé.


Les SortedSet: (Framework 4)
Collections générique. Un SortedSet maintient un ordre trié à mesure que les éléments sont insérés et supprimés sans que les performances en soient affectées.Les éléments dupliqués ne sont pas autorisés.

Il est possible de créer un comparer qui sera utilisé par le tri.

 Dim mediaFiles1 As SortedSet(Of String) = New SortedSet(Of String)(New ByFileExtension)
 
 'on crée un comparer:
  Public Class ByFileExtension
        Implements IComparer(Of String)
....
End Class

V-I-8. Queue

Collection d'objets de type FIFO (First In, First Out)

Premier arrivé premier servi.

C'est la queue devant un cinéma, le premier arrivé, prend son billet le premier.

Les objets (String, Integer....) stockés dans Queue sont insérés à une extrémité et supprimés à l'autre.

Le nombre d'élément de la queue est géré automatiquement.

DeQueue supprime et retourne l'objet de début de liste.

EnQueue ajoute un objet en fin de liste.

Peek retourne l'objet de début sans le supprimer.


Dim myQ As New Queue()
myQ.Enqueue("One")
myQ.Enqueue("Two")
myQ.Enqueue("Tree")


Console.WriteLine ( myQ.Count) 'Affiche le nombre d'éléments.
 

Console.WriteLine (myQ.Dequeue()) 
Affiche le premier sorti en le sortant. "one" dans notre exemple. S'il n'y a plus d'élément cela lève une exception (une erreur) il faut donc gérer l'exception ou contrôler le nombre d'élément avec la propriété Count.

If MyQ.Count>0 then

    myQ.Dequeue..

End If

Console.WriteLine (myQ.Peek()) 
Affiche le premier élément sans l'enlever de la Queue

myQ.Clear() 
Efface tous les éléments de la queue


Les Queue(Of..) sont des Queue mais avec un généric.


V-I-9. Stack

Collection d'objets de type pile ( ou stack) LIFO (Last In, First Out)

Dernier entré, premier sortie.

Ce type de stack (pile) est très utilisé en interne par les programmes informatiques: on stocke dans une stack les adresses de retour des procédures appelées, au retour on récupère l'adresse du dessus.

Push insère un objet en haut de la pile

Pop enlève et retourne un objet en haut de la pile

On peut utiliser une pile dans un programme pour gérer le déplacement de l'utilisateur dans un arbre, les éléments en cours sont stockés par Push, pour remonter en chemin inverse, on Pop.

warning Attention le premier élément est ici l'élément 1 (élément d'index 1 à count)
Exemple:

Dim MaPile As New Stack()

Dim Str As String

'Ajouter des éléments à la pile

MaPile.Push ("A")

MaPile.Push ("B")

MaPile.Push ("C")

'Récupérer un objet de la pile:

 Srt =MaPile.Pop()
Str est maintenant égal à "C"

warning Attention, si Option Explicit=On, les éléments de la pile étant des objets, on ne peut pas les affecter à une variable String, il faut écrire:

Str = CType(MaPile.Pop(), String)    'on convertit (cast) l'objet en String
Si la pile est vide et que l'on 'Pop', une exception non gérée du type 'System.InvalidOperationException' se produit.(une erreur se produit et cela plante!!), là aussi vérifier que MaPile.Count (qui indique le nombre d'éléments dans la pile) n'est pas égale à 0 avant de 'Poper'.

Mapile.Clear()     'Supprime tous les objets.

Les Stack(Of..) sont des track mais avec un généric.



V-I-10. Les LinkedList (Of)

Ce sont des Listes Chaînées de générique, chaque élément comportant une propriété Value(qui contient la valeur de l'élément), Next et Previous. A partir d'un élément, on peut connaître le suivant ou le précédent.

Voir le chapitre sur les algorithmes qui explique la notion de liste chaînée.

Schémas d'une liste chainée:


Imports System.Collections.Generic 

' Création d'une list. 

Dim words() As String = {"the", "fox", "jumped", "over", "the", "dog"} 

' Création d'une Linkedlist. 

Dim lk As New LinkedList(Of String)(words)

 Ajouter le mot 'today' au début.

 lk.AddFirst("today")

'Effacer le dernier élément.

 lk.RemoveLast()

'Les éléments sont des LinkedListNode, on peut en chercher un avec Find FindFirst, FindLast.

Dim current As LinkedListNode(Of String) = lk.FindLast("the")

 

'A partir de l'élément courant, on peut ajouter avant ou après.

lk.AddAfter(current, "old")  'il y a aussi AddBefore

'A partir de l'élément courant, on peut parcourir la linkedList

Dim element As LinkedListNode(Of String) = current.Previous  'il y a aussi Next

'On peut déplacer un élément

lk.AddBefore(current, element)

'On peut voir le contenu d'un LinkedListNode

current.Value

current.Previous.Value

'on peut voir la valeur du premier ou du dernier élément:

lk.First.Value

lk.Last.Value

'Il existe aussi

Containst, Count


V-I-11. HashSet (Of)

Travailler sur les ensembles.

Il s'agit d'une collection de génériques sans ordre qui contient des éléments uniques. HashSet possède comme toutes les collections Add, Remove et Contains.. et fournit plusieurs opérations d'ensembles (notamment l'union, l'intersection et la différence symétrique) ce qui permet de prendre en charge la plupart des opérations mathématiques qui sont généralement réalisées sur des ensembles (sens mathématique du terme).

Dim hs As New HashSet(Of String)

'Ajout d'éléments:

hs.Add("toto")

hs.Add("lulu")

hs.Add("titi"
La méthode Add renvoie True ou False pour indiquer si elle a fonctionné (s'il n'y avait pas déjà dans la HashSet l'élément que l'on veut ajouter).

Dim caMarche As Boolean = hs.Add("toto")  'retourne False 

hs.Count 'donne le nombre d'élément. 

On peut effacer un élément:

hs.Remove("lulu") 
On peut effacer sous condition:

Exemple: effacer tous les éléments contenant un "t":

hs.RemoveWhere( Adress Of Test) 
'La fonction Test reçoit chaque string de la table et retourne un booléen qui indique si la condition est remplie ce qui déclenche le Remove.

Private Shared Function Test(ByVal s As String) As Boolean  

    Return (Instr(s,"t")<>0) 

End Function 

On peut ajouter la collection hs2 à hs grâce à UnionWith:

hs.UnionWith(hs2) 
Les éléments doublons (qui existent déjà dans hs) ne sont pas ajoutés.

Cela correspond à un And.


On peut rechercher les éléments communs à hs2 et à hs grâce à IntersectWith:

hs.IntersectWith(hs2) 
hs contient maintenant les éléments qui étaient présents dans hs et hs2

Cela correspond à un Or.


On supprime tous les éléments de hs qui sont aussi contenus dans la collection passée en paramètre (hs2) avec ExceptWith.

hs.ExceptWith(hs2) 
hs contient maintenant les éléments qui n'étaient pas présents dans hs et hs2.


On peut rechercher les éléments contenus dans hs2 et dans hs mais pas dans les 2 grâce à SymmetricExceptWith:

hs.SymmetricExceptWith(hs2) 
hs contient maintenant les éléments qui étaient présents dans hs ou hs2 mais pas les deux.


On peut rechercher si hs2 est un sous-ensemble de hs grâce à IsSubsetOf:

Dim b As Boolean= hs.IsSubsetOf(hs2) 
b est égal à True si hs est un sous ensemble de hs2 (tous les éléments de hs sont dans hs2).

Il existe aussi:

IsProperSubstOf qui retourne True si hs est un sous-ensemble de hs2 et si hs différent de hs2 (sous ensemble strict).


On peut rechercher si hs2 est un sur-ensemble de hs grâce à IsSupersetOf:

Dim b As Boolean= hs.IsSupersetOf(hs2) 
b est égal à True si hs est un sur ensemble de hs2 (tous les éléments de hs2 sont dans hs).

Il existe aussi:

IsProperSupersetOf qui retourne True si hs est un sur ensemble de hs2 et si hs est différent de hs2 (sur ensemble strict).



V-I-12. BitArray

Crée une collection de booléens (codés sur un bit). La valeur de chaque élément est True ou False.

 'Creation de BitArray.
Dim myBA As New BitArray(5)    'BitArray de 5 bits

Dim myBA As New BitArray(5, False) 'BitArray de 5 bits à False

Dim myBA() As Boolean = {True, True, False, False, False}
Dim myBA As New BitArray(myBytes) 'on crée un  tableau de Booleans que l'on met dans le BitArray
Le premier élément est l'élément 0.

On peut mettre tous les bits à True avec SetAll:

myBA.SetAll(True)
' Mettre le dernier Bit à False avec Set.

myBA.Set(myBA.Count - 1, False)
'Obtenir la valeur du second Bit.

myBA.Get(1)
myBA(1) ou myBA.Item(1) donnent aussi la valeur du second Bit.

On peut effectuer des opérations logiques entre 2 BitArray (Or, Xor, And Not):

Exemple pour Or:

myBA1.Or(myBA2)
Count et Length donnent le nombre d'éléments, mais Count est en lecture seule, Length permet, lui, de modifier le nombre d'éléments.


La Collection BitVector32:

Ne permet de travailler que sur 32 bits mais est plus rapide.

Il faut avoir ajouté: Imports System.Collection.Specialized.



V-I-13. StringCollection

L'espace System.Collections.Specialized fournit ces nouveaux types de collection très spécifiques, elles ne sont faites que pour un seul type:

StringCollection ne peut contenir que des chaînes (cela devrait aller plus vite)

' Créer une StringCollection.
Dim myCol As New StringCollection()

'Créer un tableau de String, l'ajouter( en fin) à la collection.
Dim myArr() As [String] = {"rouge", "vert", "orange", "vert",)
myCol.AddRange(myArr)

'Ajouter un élément à la fin de la collection
myCol.Add("marron")

'Insérer un élément à l'index 3
myCol.Insert(3, "bleue")

'Enlever un élément
myCol.Remove("orange")


' chercher et enlever tous les éléments "vert" 
Dim i As Integer = myCol.IndexOf("vert")
While i > - 1
myCol.RemoveAt(i)
i = myCol.IndexOf("vert")
End While

' La collection contient t'elle "jaune"?
If myCol.Contains("jaune") Then..

' Copie la collection dans un tableau.
Dim myArr2(myCol.Count) As [String]
myCol.CopyTo(myArr2, 0)

' Efface toutes les strings de la Collection.
myCol.Clear()
 

'Afficher la liste des Strings

Dim myEnumerator As System.Collections.IEnumerator = myCol.GetEnumerator()

While myEnumerator.MoveNext()
Console.WriteLine(" {0}", myEnumerator.Current)
End While
'C'est un peu complexe!! on y reviendra.
warning Attention le premier élément est ici l'élément 0 (l'index va de 0 à count-1); c'est du .NET!!


V-I-14. ObservableCollections, SortedSet(Of T)

Pour mémoire on se souvient qu'il existait un Type Collection en VB6, de Base 1, à oublier.


Par contre, à partir de VB 2008 existent les collections ObservableCollections qui peuvent être 'Bindées' (attachées) à des Objets visuels (comme une List ou une Grid WPF) et qui permettent la mise à jour automatique du contrôle quand on modifie la collection.


Enfin, à partir de VB 2010 existent SortedSet(Of T) . Un SortedSet(Of T) maintient un ordre trié à mesure que les éléments sont insérés et supprimés sans que les performances en soient affectées.Les éléments dupliqués ne sont pas autorisés.


V-I-15. Généralisation de la notion de collection

Certains objets ont une liste de données, d'items, Vb les organise en Collections.

Une collection peut donc faire partie des propriétés d'un objet.

Exemple:

On verra plus loin qu'un contrôle nommé TextBox peut contenir du texte, ce contrôle à une collection nommée .lines qui contient les lignes de texte (s'il y en a plusieurs)

Si le texte contient 3 lignes, elles seront dans la collection 'lines'.

Texbox1.lines(0)    'remarquer, ici le premier élément est 0!!

Textbox1.lines(1)

Textbox1.lines(2) 
L'indice des éléments va de 0 à count-1

Autres exemples:

Les contrôles ListBox possèdent une collection 'Items' dans laquelle sont placés tous les éléments contenus dans la liste. Pour ajouter un élément on utilise la méthode Add de la collection Items:

ListBox.Items.Add( )

Un tas d'objets possèdent des collections.

Encore plus: chaque formulaire possède une Collection 'Controls'. Il s'agit d'une collection qui contient tous les contrôles de ce formulaire.



V-I-16. Pourquoi le premier élément est-il 0 ou 1 ?

warning Le .NET Framework normalise les collections comme étant des collections de base zéro (ArrayList par exemple). Visual Basic fournit des collections de base 1 (Comme Collection qu'il ne faut plus utiliser).

V-I-17. Exemples sur les collections

Créer une ArrayList, une queue, ajouter la queue à la ArrayList, chercher un élément, insérer un élément.

Les collections font partie de l'espace de nom Systeme.Collections

Imports System.Collections


' Créer une ArrayList.
Dim myAL As New ArrayList()
myAL.Insert(0, "un")
myAL.Insert(1, "deux")

' Créer une Queue.
Dim myQueue As New Queue()
myQueue.Enqueue("trois")
myQueue.Enqueue("quatre")


' Copies la Queue dans ArrayList à l'index 1.
myAL.InsertRange(1, myQueue)


' Chercher "deux" et ajouter "moins de deux" avant .
myAL.Insert(myAL.IndexOf("deux"), "moins de deux")


' Ajouter "!!!" à la fin.
myAL.Insert(myAL.Count, "!!!")


V-I-18. Lexique anglais=>Français

Array = tableau, table.

length= longueur

Key= clé

Remove (to)= enlever

Stack= tas



V-J. Les 'Structures'

En règle générale, une structure est utilisée comme conteneur pour un petit jeu de variables.
Permet de regrouper des données de type différent:

(En Vb6 il y avait les types définis par l'utilisateur, ils sont remplacés par les structures.)

info Les structures sont intéressantes quand vous voulez utiliser des variables contenant plusieurs informations de différent type. Les structures sont surtout utilisées dans la programmation non 'objet'(En programmation Objet, on utilisera plutôt les Collections).

Exemple :

Vous voulez définir une variable contenant une adresse composée d'un numéro, de la rue, de la ville.

Il faut d'abord définir la structure (au niveau Module ou Class, pas dans une procédure).

Public Structure Adresse

   Dim Numero     As Integer

   Dim Rue        As String

   Dim Ville      As String

End Structure

Puis dans une procédure il faut déclarer la variable :

Dim MonAdresse As Adresse
La variable MonAdresse est déclarée comme une adresse, elle contient donc:

un numéro qui est dans 'MonAdresse.Numero'

un nom de rue qui est dans 'MonAdresse.Rue'

un nom de ville qui est dans 'MonAdresse.Ville'


On pourra enfin l'utiliser :

MonAdresse.Numero=2

MonAdresse.Rue= "Grande rue"

MonAdresse.Ville= "Lyon"
On peut aussi utiliser le mot clé With pour ne pas avoir à répéter le nom de la variable (et cela va plus vite).

With MonAdresse

    .Rue= "Grande rue"

    .Ville= "Lyon"

End With
With est utilisable sur tous les objets.


Il est possible de travailler sur un tableau de structures:

Dim Adresses(99) as Adresse    'Permet de travailler sur un tableau de 100 adresses

Adresses(33).Rue="Place de la mairie"
On peut utiliser une variable de type structure comme paramètre d'une fonction:

Sub AfficheAdresse( ByVal  Une Adresse As Adresse)

...Imprimer l'adresse

End sub
Pour imprimer l'adresse 33 on écrira AfficheAdresse ( Adresse(33))



V-J-1. Tableau dans une structure

Attention quand dans une structure il y a un tableau, il faut l'initialiser:

on veut définir une structure dans laquelle il y a 25 données DriveNumber.

On aurait tendance à écrire:

Public Type DriveInfo

   DriveNumber(25) As Integer 'FAUX

   DriveType As String

End Type
Mais cela ne fonctionne pas!!

En Visual Basic .NET il y a 2 méthodes pour utiliser un tableau dans une structure:

1-Méthode par initialize

Une structure peut comporter une méthode 'Initialize' qui sera exécutée quand on déclare une variable de type structure.

Ici, on a crée une méthode Initialize qui redimensionne le tableau interne à la structure.

Public Structure DriveInfo

   Dim DriveNumber() As Short

   'Noter que le nombre d'élément a disparu.

   Dim DriveType As String

   'maintenant on instance les 25 éléments.

   Public Sub Initialize()

      ReDim DriveNumber(25)

   End Sub

End Structure
Exemple de routine utilisant la structure.

Function AddDrive(ByRef Number As Short, ByRef DriveLabel As String) As Object

   Dim Drives As DriveInfo

   Drives.Initialize()

   Drives.DriveNumber(0) = 123

   Drives.DriveType = "Fixed"

End Function

2-Autre manière de faire:

Après la déclaration de la variable, on 'Redimensionne' le tableau.

Public Structure DriveInfo

   Dim DriveNumber() As Short

   Dim DriveType As String

End Structure

 

Function AddDrive(ByRef Number As Short, ByRef DriveLabel As String) As Object

   Dim Drives As DriveInfo

   Redim Drives.DriveNumber(25)

   Drives.DriveNumber(3)=12

   Drives.DriveType = "Fixed"

End Function

Si on utilise 100 variables Drives, il faut 'Redim' ou 'Initialize' le tableau pour chaque variable!!

Dim Drives (100) As DriveInfo

 

For i as Integer =0 to 100

Drives (i).Initialize                    'Dur dur!!

Next i
En plus si Dim Drives (100) est en tête d'un module, il faut mettre la boucle dans une procédure.



V-J-2. Allons plus loin

Une structure hérite de System.ValueType


V-J-2-a. Les structures sont des types 'valeur'

Une variable d'un type structure contient directement les données de la structure, alors qu'une variable d'un type classe contient une référence aux données, ces dernières étant connues sous le nom d'objet.

Cela a de l'importance: si je crée une variable avec une structure, que je copie cette variable dans une seconde, le fait de modifier la première variable ne modifie pas la seconde.

Prenons l'exemple donné par Microsoft:

Structure Point
   Public x, y As Integer
   Public Sub New(x As Integer, y As Integer)
      Me.x = x
      Me.y = y
   End Sub
End Structure 
On définit une structure Point et on définit une méthode 'New' permettant de saisir les valeurs:

'Public Sub New' est un constructeur.

Pour saisir les valeurs de x et y ont peut utiliser:

Dim a As Point
a.x=10
a.y=10
ou utiliser le constructeur:

Dim a As New Point(10,10)  
En partant de la déclaration ci-dessus, le fragment de code suivant affiche la valeur 10 :

Dim a = new Point(10, 10)
Dim b = a
a.x = 100
Console.WriteLine(b.x)	'b est donc bien différent de a
L'assignation de a à b crée une copie de la valeur, et b n'est donc pas affecté par l'assignation à a.x. Si, en revanche, Point avait été déclaré comme une classe, la sortie aurait été 100 puisque a et b auraient référencé le même objet.

Enfin, les structures n'étant pas des types 'référence', il est impossible que les valeurs d'un type structure soient nulles ( elles sont égales à 0 après la création).


V-J-2-b. Les structures peuvent contenir plein de choses

On a vu qu'elles peuvent contenir:

- Des variables de différent type.

- Des tableaux.

- Des méthodes : on a vu l'exemple de Initialize et de New.

Mais aussi

- Des objets.

- D'autres Structures.

- Des procédures.

- Des propriétés.


Exemple donné dans l'aide (et modifié par moi) :

Débutant: A relire peut-être ultérieurement quand vous saurez utiliser les Classes.

Cet exemple définit une structure Employee contenant une procédure CalculBonus et une propriété Eligible.

Public Structure Employee
Public FirstName As String
Public LastName As String
' Friend members, accessible partout dans le programme.
Friend EmployeeNumber As Integer
Friend WorkPhone As Long
' Private members, accessible seulement dans la structure.
Private HomePhone As Long
Private Level As Integer
Public Salary As Double
Public Bonus As Double
  ' Procedure .
  Friend Sub CalculateBonus(ByVal Rate As Single)
   Bonus = Salary * CDbl(Rate)
  End Sub
' Property pour retourner l'éligibilité d'un employé.
  Friend ReadOnly Property Eligible() As Boolean
    Get
      Return Level >= 25
    End Get
  End Property
End Structure
Utilisons cette structure:

Dim ep As Employee    'Déclaration d'une variable Employee

ep.Salary = 100       'On saisit le salaire 

ep.CalculateBonus(20) 'On calcule le bonus

TextBox1.Text = ep.Bonus.ToString    'On affiche le bonus

Cela ressemble aux Classes !! Non?


V-J-2-c. Portée

Vous pouvez spécifier l'accessibilité de la structure à l'aide des mots clé: Public, Protected, Friend ou Private ou garder la valeur par défaut, Public. Vous pouvez déclarer chaque membre en spécifiant une accessibilité. Si vous utilisez l'instruction Dim sans mot clé, l'accessibilité prend la valeur par défaut, Public.

Private Mastructure

    Public i As Integer

    ...

End Structute

En conclusion les structures sont maintenant très puissantes et peuvent contenir autant de choses que les Classes , on verra cela plus loin. Mais les structures sont référencées 'par valeur' alors que les Classes le sont 'par référence'.


 

Les sources présentés sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © . Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.

Vos questions techniques : forum d'entraide Accueil - Publiez vos articles, tutoriels, cours et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones. Nous contacter - Copyright 2000..2005 www.developpez.com