Sommaire
1.
Définition de collections
PAGEREF _Toc164142909 \h 2
1.1.
Un énumérateur.
PAGEREF _Toc164142910 \h 2
1.2.
Membres de la synchronisation.
PAGEREF _Toc164142911 \h 2
1.3.
Capacité et décompte.
PAGEREF _Toc164142912 \h 3
1.4.
Collections fréquemment utilisées.
PAGEREF _Toc164142913 \h 3
2.
Sélection d'une classe de collection_
PAGEREF _Toc164142914 \h 4
3.
Présentation des collections ArrayList et hashTable
PAGEREF _Toc164142915 \h 6
3.1.
Créons cEmploye
PAGEREF _Toc164142916 \h 6
3.2.
ArrayList
PAGEREF _Toc164142917 \h 7
3.3.
HashTable
PAGEREF _Toc164142918 \h 8
4.
Exemple
PAGEREF _Toc164142919 \h 9
4.1.
Trier des objets selon une de leur propriété.
PAGEREF _Toc164142920 \h 10
4.2.
Je voudrais maintenant les trier suivant leur taille.
PAGEREF _Toc164142921 \h 11
Une collection est un ensemble d'objets du même type qui sont regroupés
ensemble. Les objets d'un type quelconque peuvent être regroupés en une
collection du type
Object afin de tirer parti des
constructions inhérentes au langage.
Par exemple, l'instruction for each en Visual Basic s'attend à
ce que tous les objets de la collection soient du même type.
Cependant, dans une collection de type Object, les différents
éléments sont soumis à un traitement supplémentaire, des opérations boxing et
unboxing ou des conversions par exemple, qui pénalise les performances de la
collection.
Les conversions boxing et unboxing se produisent généralement en cas de
stockage ou d'extraction d'un type valeur dans une collection de type Object.
Les collections génériques, telles que
List, et les collections non
génériques fortement typées, telles que
StringCollection, évitent cette
dégradation des performances si le type de l'élément est le type auquel la
collection est destinée (par exemple, le stockage ou l'extraction de chaînes à
partir de StringCollection).
En outre, les collections fortement typées exécutent automatiquement la
validation du type de chaque élément ajouté à la collection.
Toutes les collections qui implémentent directement ou indirectement
l'interface
ICollection ou l'interface
générique
ICollection partagent plusieurs
fonctionnalités en plus des méthodes permettant d'ajouter, de supprimer ou de
rechercher des éléments :
1.1.
Un énumérateur.
Un énumérateur est
un objet qui effectue une itération sur la collection qui lui est associée. Il
peut être considéré comme un pointeur mobile vers un élément quelconque de la
collection.
Un énumérateur ne
peut être associé qu'à une seule collection, mais une collection peut avoir
plusieurs énumérateurs. L'instruction for each en Visual Basic utilise
l'énumérateur et masque la complexité de manipulation de celui-ci.
1.2.
Membres de la synchronisation.
La synchronisation
garantit la sécurité des threads lors de l'accès à des éléments de la
collection. Par défaut, les collections ne sont pas thread-safe. Seules quelques
classes de l'espace de noms
System.Collections
fournissent une méthode Synchronize qui crée un wrapper thread-safe
par-dessus la collection.
Cependant, toutes
les classes de l'espace de noms System.Collections fournissent une
propriété SyncRoot que des classes dérivées peuvent utiliser pour créer
leur propre wrapper thread-safe. Une propriété IsSynchronized est
également fournie pour déterminer si la collection est thread-safe.
La synchronisation
n'est pas disponible dans l'interface générique ICollection.
Méthode CopyTo
.
Toutes les
collections peuvent être copiées dans un tableau à l'aide de la méthode
CopyTo ; toutefois, l'ordre des éléments dans le nouveau tableau dépend de
la séquence dans laquelle l'énumérateur les retourne. Le tableau résultant est
toujours unidimensionnel avec une limite inférieure de zéro.
Notez que l'interface générique ICollection possède des membres
supplémentaires que l'interface non générique n'inclut pas.
Les fonctionnalités suivantes sont implémentées dans certaines classes
de l'espace de noms System.Collections :
1.3.
Capacité et décompte.
La capacité d'une
collection est le nombre d'éléments qu'elle peut contenir. Le décompte d'une
collection est le nombre d'éléments qu'elle contient réellement.
BitArray est un cas spécial ; sa
capacité équivaut à sa longueur, qui est la même que son décompte. Certaines
collections masquent la capacité ou le décompte, ou les deux.
Toutes les
collections de l'espace de noms System.Collections étendent
automatiquement leur capacité lorsque la capacité actuelle est atteinte. La
mémoire est réallouée et les éléments sont copiés de l'ancienne collection vers
la nouvelle. Le code nécessaire pour utiliser la collection est ainsi réduit,
mais les performances de la collection peuvent quand même s'en ressentir. La
meilleure façon d'éviter la dégradation des performances due à des réallocations
multiples est de définir une capacité initiale égale à la taille estimée de la
collection.
Limite
inférieure.
La limite
inférieure d'une collection est l'index de son premier élément. Toutes les
collections indexées dans l'espace de noms System.Collections ont une
limite inférieure de zéro.
Array possède par défaut une
limite inférieure de zéro, mais une limite inférieure différente peut être
définie lors de la création d'une instance de la classe Array à l'aide de
CreateInstance.
Les classes System.Collections sont généralement réparties en
trois catégories :
1.4.
Collections fréquemment utilisées.
Il s'agit des
variations communes des collections de données, telles que les tables de
hachage, les files d'attente, les piles, les dictionnaires et les listes. Les
collections fréquemment utilisées possèdent des versions génériques et des
versions non génériques.
Collections
binaires.
Il s'agit de
collections dont les éléments sont des bits indicateurs. Leur comportement est
un peu différent de celui des autres collections.
Collections
spécialisées.
Ces collections
répondent à des objectifs hautement spécifiques ; il s'agit généralement de
gérer un élément de type spécifique, tel que
StringDictionary.
Veillez à choisir votre classe de collection avec beaucoup de soin. Si
chaque collection a sa propre fonctionnalité, elle a également ses propres
limites. Plus une collection est spécialisée, plus elle est limitée. Pour des
conseils sur le choix d'une collection.
2.
Sélection d'une classe de collection
Veillez à choisir votre classe
System.Collections avec beaucoup
de soin. Le choix d'une collection erronée peut limiter l'usage que vous pouvez
en faire.
Réfléchissez aux questions suivantes :
Avez-vous besoin
d'une liste séquentielle dans laquelle l'élément est généralement abandonné une
fois sa valeur récupérée ?
Si oui, vous devez
envisager d'utiliser la classe
Queue ou la classe générique
Queue si vous avez besoin d'un
comportement de premier entré premier sorti (FIFO).
Vous devez
envisager d'utiliser la classe
Stack ou la classe générique
Stack si vous avez besoin d'un comportement de dernier entré premier sorti (LIFO).
Sinon, vous devez
envisager d'utiliser les autres collections.
Devez-vous accéder
aux éléments dans un ordre précis, tel que FIFO, LIFO ou dans un ordre
aléatoire ?
La classe Queue
et la classe générique Queue proposent un accès FIFO.
La classe Stack
et la classe générique Stack proposent un accès LIFO.
La classe générique
LinkedList autorise un accès
séquentiel à partir du début ou de la fin.
Les autres
collections offrent un accès aléatoire.
Avez-vous besoin
d'accéder à chaque élément par son index ?
Les classes
ArrayList et
StringCollection et la classe
générique
List offrent l'accès à leurs
éléments par l'index de base zéro de l'élément.
Les classes
Hashtable,
SortedList,
ListDictionary et
StringDictionary, et les classes génériques
Dictionary et
SortedDictionary, offrent l'accès à leurs
éléments par la clé de l'élément.
Les classes
NameObjectCollectionBase et
NameValueCollection, et les classes
génériques
KeyedCollection et
SortedList, offrent l'accès à leurs
éléments par l'index de base zéro ou par la clé de l'élément.
Chaque élément contiendra-t-il une seule
valeur, une combinaison d'une clé et d'une valeur ou une combinaison d'une clé
et de plusieurs valeurs ?
Une valeur : utilisez l'une des collections
basée sur l'interface
IList ou l'interface générique
IList.
Une clé et une valeur : utilisez l'une des
collections basée sur l'interface
IDictionary ou l'interface générique
IDictionary.
Une valeur avec clé
incorporée : utilisez la classe générique KeyedCollection.
Une clé et
plusieurs valeurs : utilisez la classe NameValueCollection.
Avez-vous besoin de
trier les éléments dans un ordre différent de celui dans lequel ils ont été
entrés ?
La classe
Hashtable trie ses éléments par leurs codes de hachage.
La classe
SortedList et les classes génériques SortedDictionary et
SortedList trient leurs éléments par la clé, selon les implémentations de
l'interface
IComparer et de l'interface
générique
IComparer.
ArrayList
fournit une méthode
Sort qui prend une
implémentation IComparer comme paramètre. Son équivalent générique, la
classe générique List, fournit une méthode
Sort qui prend une
implémentation de l'interface générique IComparer comme paramètre.
Avez-vous besoin
d'opérations de recherche et de récupération d'informations rapides ?
ListDictionary
est plus rapide que Hashtable pour les petites collections (10 éléments
ou moins). La classe générique SortedDictionary fournit une capacité de
recherche plus rapide que la classe générique Dictionary.
Avez besoin de
collections qui acceptent uniquement des chaînes ?
StringCollection
(sur la base de IList) et StringDictionary (sur la base de
IDictionary) figurent dans l'espace de noms
System.Collections.Specialized.
En outre, vous
pouvez utiliser l'une des classes de collections génériques dans l'espace de
noms
System.Collections.Generic
comme collection de chaînes fortement typée en spécifiant la classe
String de leurs arguments de
type générique.
3.
Présentation des collections ArrayList
et hashTable
Ce premier
article vous montre comment implémenter cet objet. Le but va être de créer une
classe collection cEmployes d'objets cEmploye.
3.1.
Créons cEmploye
Cette classe est
simple:
Public Class cEmploye
Private m_sNom As String
Public Property Nom() As String
Get
Nom = m_sNom
End Get
Set
m_sNom = Value
End Set
End Property
Public Sub New(ByVal sNom As String)
Nom = sNom
End Sub
End Class
Remarquez que
nous avons redéfinit le constructeur. On impose ainsi qu'une classe cEmploye ne
peut être créée que si l'on donne un nom à notre employé :
Dim objE = New cEmploye("IDRISSI Ahmed")
Dans un premier
temps, on va ajouter une variable privée à notre classe cEmployes :
Public Class cEmpoyes
Private mCol As Microsoft.VisualBasic.Compatibility.VB6.Collection
Public Sub New()
mcol = New Microsoft.VisualBasic.Compatibility.VB6.Collection()
End Sub
...
End Class
Pour
implémenter l'ajout d'un employé :
Public Function Add(ByVal sNom As String, ByVal sKey As
String) As cEmploye
Dim objE As New cEmploye(sNom)
mcol.Add(objE, sKey)
Add = objE
End Function
Vous voyez que
par défaut, j'impose l'utilisation d'une clé .
Pour les autres méthodes et propriétés (Item, Count et Remove),
Reste maintenant
à permettre au consommateur de notre classe de pouvoir faire des itérations.
C'est maintenant
beaucoup plus simple, il suffit d'utiliser l'interface IEnumerator mise à
disposition par l'objet Collection :
Public Function GetEnumerator() As IEnumerator
GetEnumerator = mcol.GetEnumerator
End Function
On peut faire
maintenant de l'itération sur notre objet :
Dim c As New cEmpoyes()
c.Add("Richard Clark", "clé")
For Each objTemp In c
Debug.WriteLine(objtemp.Nom)
Next
On va maintenant
utiliser une autre classe de type collection : ArrayList.
3.2.
ArrayList
Comme son nom
l'indique, cette classe stocke des objets dans un tableau dynamique (sans clé).
Notre classe cEmploye est la même. En revanche, la classe cEmploye a quelque
peut changé.En voici le code complet :
Public Class cEmployes
Private mCol As ArrayList
Public Sub New()
mCol = New ArrayList()
End Sub
Public Function GetEnumerator() As IEnumerator
GetEnumerator = mCol.GetEnumerator
End Function
Public Function Add(ByVal sNom As String) As cEmploye
Dim objE As New cEmploye(sNom)
mCol.Add(objE)
Add = objE
End Function
Public ReadOnly Property Item(ByVal iIndex As Integer) As cEmploye
Get
Item = mCol.Item(iIndex)
End Get
End Property
Public ReadOnly Property Count() As Integer
Get
Count = mCol.Count
End Get
End Property
Public Sub Remove(ByVal sKey As String)
mCol.Remove(sKey)
End Sub
End Class
Le principe est
donc identique. En revanche, pour obtenir un élément dans la collection, il faut
connaitre son index.
Autre type de
collection est : HashTable.
3.3.
HashTable
Cette fois-ci,
cette collection associe à chaque élément de la collection une clé obligatoire.
Public Class cEmployes
Private mHashCol As Hashtable
Public Sub New()
mHashCol = New Hashtable()
End Sub
Public Function GetEnumerator() As IEnumerator
GetEnumerator = mHashCol.Values.GetEnumerator
End Function
Public Function Add(ByVal sNom As String, ByVal sKey As String) As
cEmploye
Dim objE As New cEmploye(sNom)
mHashCol.Add(sKey, objE)
Add = objE
End Function
Public ReadOnly Property Item(ByVal sKey As String) As cEmploye
Get
Item = mHashCol.Item(sKey)
End Get
End Property
Public ReadOnly Property Count() As Long
Get
Count = mHashCol.Count
End Get
End Property
Public Sub Remove(ByVal sKey As String)
mHashCol.Remove(sKey)
End Sub
End Class
Vous aurez
remarqué que l'itération se fait sur le tableau des valeurs :
GetEnumerator = mHashCol.Values.GetEnumerator
4.
Exemple
selon une propriété avec IComparable mais
également comment la trier suivant plusieurs propriétés avec des IComparer (sans
écrire le moindre algo de tri)
C'est en lisant
un thread sur un newsgroup que j'ai vu cette astuce (j'avoue ne pas avoir noté
le nom de la personne qui donnait cette astuce mais si elle se reconnait,
qu'elle n'hésite pas à me le dire,
Bref, la
question était la suivante :
4.1.
Trier des objets selon une de leur
propriété.
Avec le
Framework, no problemo, il suffit de lui implémenter l'interface IComparable et
la plupart des objets collection du Framework feront le travail pour vous.
Prenons l'exemple d'une classe Personne avec les propriétés suivantes :
Classe Personne | |
Nom | string |
Age | int |
Taille | float |
Maintenant,
remplissons un ArrayList de Personnes :
oAr.Add(new Personne("Said", 40,1.7f));
oAr.Add(new Personne("Ahmed", 30,1.5f));
oAr.Add(new Personne("Mounir", 20,1.6f));
oAr.Add(new Personne("Kamal", 10,1.8f));
Nous voulons que
par défaut, il soit trié suivant le Nom de la Personne. Implémentons donc
IComparable dans la classe Personne :
public class Personne : IComparable
{
public int CompareTo(object obj)
{
if (obj.GetType() != typeof(Personne))
throw new ArgumentException("Impossible de comparer les
choux et les carottes");
return this.Nom.CompareTo(((Personne) obj).Nom);
}
//
//
}
Pour trier
l'ArrayList, il suffit alors d'utiliser sa méthode Sort :
oAr.Sort();
Et voilà, notre
collection est triée suivant le Nom. Fastoche. Quoi ? Vous dites ? Ah, vous avez
une autre question ? Et alors ?
4.2.
Je voudrais maintenant les trier suivant
leur taille.
C'est là ou
l'astuce intervient (remarquez, il suffit de le savoir). La méthode Sort de l'ArrayList
a plusieurs signatures, 3 pour être précis. La signature qui nous intéresse ici
attends juste un argument, un IComparer. C'est lui qui va nous aider a trier les
personnes suivant leur taille.
Créons donc une
classe, implémentant IComparer (que l'on déclarera interne à la Personne car
elle ne s'applique qu'à elle) et comparant les tailles :
public class Personne : IComparable
{
public class TailleComparer : IComparer
{
public int Compare(object x, object y)
{
if (x.GetType() != typeof(Personne) y.GetType() != typeof(Personne))
throw new ArgumentException("Impossible de comparer les
choux et les carottes");
return ((Personne) x).Taille.CompareTo(((Personne) y).Taille);
}
}
//
//
}
C'est tout.
Maintenant pour trier notre ArrayList suivant la taille, une ligne suffit :
oAr.Sort(new Personne.TailleComparer());
Vous pouvez
ainsi implémenter une autre classe pour comparer les Personnes suivant leur age.
Aucun commentaire:
Enregistrer un commentaire