Alternative aux Structures

Résolu
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013 - 11 mars 2011 à 20:34
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 - 13 mars 2011 à 19:24
Bonjour à tous,
c'est la premiere fois que je poste pour vous demandez votre aide.
Jusque là j'utilisais les sructures pour déclarer mes variables du type :
[i]Structure Personne
Public Nom as string
Public Age as String
End Structure/i

Ensuite je déclare un tableau de personne :
Public Personnes () as Personne

Puis je peux utiliser mon tableau :
Personnes (0).Nom = "Durand"
Personnes (0).Age = 40

Problème : si je supprime "Durand", cela laisse une case vide dans mon tableau et m'oblige à decaler toutes les entrées aprés l'Entrée "Durand".

J'ai des vagues notion d'objet et de collections mais je ne sais pas du tout si c'est une meilleure solution ni comment la mettre en oeuvre.

Je vous remercie d'avance pour faire partager votre experience....

20 réponses

foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
13 mars 2011 à 12:31
Voili voilou,

Par contre j'ai remplacé la structure Personne par la classe Personne, ce qui résout tous vos problèmes et est bien plus adapté à ce que vous cherchez à faire. Vous verrez que la différence de conception avec la structure n'est pas si ennorme comparé au fait qu'elle vous facilite la vie dans votre cas.

Imports System.Collections.Generic
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.IO

<Serializable()> _
Public Class Personne

    Private _nom As String
    Private _prenom As String
    Private _age As Integer

    Public Property Nom As String
        Get
            Return _nom
        End Get
        Set(ByVal value As String)
            _nom = value
        End Set
    End Property

    Public Property Prenom As String
        Get
            Return _prenom
        End Get
        Set(ByVal value As String)
            _prenom = value
        End Set
    End Property

    Public Property Age As Integer
        Get
            Return _age
        End Get
        Set(ByVal value As Integer)
            _age = value
        End Set
    End Property

    Public Sub New(ByVal nom As String, ByVal prenom As String, ByVal age As Integer)
        _nom = nom
        _prenom = prenom
        _age = age
    End Sub

End Class

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim formatter As New BinaryFormatter()
        Dim personnes As New SortedList(Of String, Personne)
        Dim unePersonne As Personne

        'Création d'une personne
        unePersonne = New Personne("Durant", "Pierre", 30)

        'Ajout de la personne à la liste
        personnes.Add(unePersonne.Nom, unePersonne)
        'ou directement
        personnes.Add("Dupond", New Personne("Dupond", "Jacques", 20))

        'Accès à l'age d'une personne
        Console.WriteLine("L'age de Mr. Durant est {0}", personnes("Durant").Age)

        'Modification de l'age d'une personne
        personnes("Dupond").Age = 22

        'Modification du nom d'une personnes
        unePersonne = personnes("Durant")
        personnes.Remove("Durant")
        unePersonne.Nom = "Durand"
        personnes.Add(unePersonne.Nom, unePersonne)

        'Sérialization de la liste de personnes
        Using fs As New FileStream("C:\maListe", FileMode.Create, FileAccess.Write)
            formatter.Serialize(fs, personnes)
        End Using

        'Déserialization de la liste de personnes
        Dim personnesDeserialize As SortedList(Of String, Personne)
        Using fs As New FileStream("C:\maListe", FileMode.Open, FileAccess.Read)
            personnesDeserialize = TryCast(formatter.Deserialize(fs), SortedList(Of String, Personne))
        End Using

        If (personnesDeserialize IsNot Nothing) Then

            'Iteration de la liste des personnes déserializée
            For Each kvp As KeyValuePair(Of String, Personne) In personnesDeserialize
                Console.WriteLine("Clé unique {0} ; Nom {1} ; Prénom = {2} ; Age = {3}", _
                                  kvp.Key, _
                                  kvp.Value.Nom, _
                                  kvp.Value.Prenom, _
                                  kvp.Value.Age)
            Next

            'Suppression d'une personne
            personnesDeserialize.Remove("Dupond")

        Else
            Console.WriteLine("Le fichier 'C:\maListe' n'est pas une liste de personnes valide")
        End If

    End Sub


Si vous avez des questions par rapport à la classe Personne, n'ésitez pas.
3
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
13 mars 2011 à 14:24
Bien sur, une fois déserializé, vous pouvez utiliser l'objet normalement. Le fait d'avoir créer une nouvelle variable personnesDeserialize et de l'avoir utilisé pour lister les personnes dans la console n'est qu'un exemple.

Vous pouvez même très bien, dans mon exemple, déserializer directement en utilisant la variable 'personnes'

'Déserialization de la liste de personnes
Using fs As New FileStream("C:\maListe", FileMode.Open, FileAccess.Read)
  personnes = TryCast(formatter.Deserialize(fs), SortedList(Of String, Personne))
End Using
3
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
11 mars 2011 à 20:49
Bonjour,

si je supprime "Durand", cela laisse une case vide dans mon tableau et m'oblige à decaler toutes les entrées aprés l'Entrée "Durand".

le mieux serait bien évidemment d'utiliser une base de données
Mais si tu veux continuer à utiliser un tableau dynamique typé comme ta structure, rien ne t'en empêche. Et tu n'as alors pas l'obligation, en cas de suppression d'un élément de ton tableau, de "tout décaler" !
Question de méthode :
1) tu substitues à l'élément supprimé le dernier élément de ton tableau
2) tu redimensionnes ton tableau à son ubound - 1
Comme dans l'affaire du sapeur camembert et de ses trous dans la cour de sa caserne
Voilà !



____________________
Vous aimez Codes-Sources ? Il vous aide ? Cliquez ici pour l'aider à continuer
Cliquer sur "Réponse acceptée" en bas d'une solution adéquate est
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
11 mars 2011 à 21:08
Merci pour cette réponse rapide et cette technique astucieuse, c'est effectivement une methode simple que je pourrais utiliser dans mon projet....
mais j'ai aussi oublier un détail...si on veux retrouver un element il faut parcourir tous le tableau.....je me demandais aussi si il n'y a pas plus efficace et comment vous procederiez.....sachant que si je souhaite retrouver un element par sa proriété Nom (l'exemple est mal choisi, j'aurais du parler du numéro de securité sociale plutôt qui lui est unique mais ce n'est qu'un exemple)
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 1
11 mars 2011 à 22:45
Bonjour BasicZX81,

Une idée ...

"Hashtable" et ContainsKey (juste pour une collection de paires clé/valeur )
http://msdn.microsoft.com/fr-fr/library/system.collections.hashtable(v=vs.80).aspx

Efficace pour la recherche, l'ajout et la suppression, (add & remove) mais limité a clé/valeur .
Mais je ne sais pas trop si cela répond a tes attentes!
Cordialement CGSI3
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
12 mars 2011 à 08:39
Bonjour GSI3,
C'est un peu l'idée mais la Hashtable se limite à 2 colonnes (clé/valeur)....
dans mon exemple je me suis arreté à "Nom" et "Age" mais il y a davantage de colonnes....

J'ai essaiyé de créer des objets dans une collection pour pouvoir utiliser la methode Indexof mais la méthode attant un objet du type Personnes(x), mais je souhaite acceder à l'element non pas avec "x" mais avec "Nom" qui je rappele est unique (mon exemple est mal choisi)....
0
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 1
12 mars 2011 à 15:14
ReBonjour BasicZX81,

j'ai récement utilisé un tableau d'élément "structure" et en parallele ce type "HashTable" en l'initialisant "par ligne" avec l'identifiant "Nom" et l' "Indice" de la ligne dans le tableau.
Tu peux ensuite utiliser les fonctions de la hashtable. (recherche, tri etc)
Et retrouver la ligne X dans le tableau tres rapidement selon le nom ...
Idem pour trier rapidement un tableau sur un seul parametre

(Je parle du nom ou d'une clé représentant l'individu genre Nom + Prenom + Age etc ...)

c'est une piste simple possible

Sinon beaucoup plus pro et compliqué ...:

http://msdn.microsoft.com/fr-fr/library/system.collections.collectionbase(v=VS.80).aspx

Voici le commentaire:
Cette classe de base facilite aux implémenteurs la création d'une collection personnalisée fortement typée. Il est préférable d'étendre cette classe de base plutôt que d'en créer une nouvelle.

Mais malheureusement je ne m'y suis pas encore frotté ...
Bonne Prog CGSI3
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
12 mars 2011 à 15:55
Merci pour ta réponses CGSI3,
J'ai effectivement explorer ta methode avec gestion d'une double table....la premiere table me servant à indexer mes données de facon à retrouver un objet rapidement et la seconde pour stocker mes objets.....mais cela s'avere un peu fastidieux à utiliser dans mon code....donc je continue les structures pour le moment....

Cela dit ca peux être une trés bonne idée d'implémenter ça dans une classe pour simplifier son utilisation mais hélas je ne sais pas implementer correctement les classes.....Je jetterrais un oeuil sur le lien que tu propose ca peux effectivement m'interresser.....

Merci beaucoup.....
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
12 mars 2011 à 21:24
Bonjour,

Voici une facon de faire possible :

Public Structure Personne
  Public Prenom as String
  Public Age as Integer

  Public Sub New(ByVal prenom as String, ByVal Age as Integer)
    Me.Prenom = prenom
    Me.Age = age
  End Sub

End Structure

Public Sub Toto()
  Dim personnes as New System.Collections.Generic.SortedList(Of String, Personne)
  
  'Ajout
  personnes.Add("Durant", new Personne("Pierre", 30))

  'Utilisation
  Console.WriteLine("Prénom de Mr.Durant = ", personnes("Durant").Prenom)
  Console.WriteLine("Agede Mr.Durant = ", personnes("Durant").Age)

  'Par contre le nom étant unique, pour le modifier il faudra faire
  Dim durant as Personne = personnes("Durant")
  personnes.Remove("Durant")
  personnes.Add("Durand", durant)

  'Suppression
  personnes.Remove("Durant")

End Sub

0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
12 mars 2011 à 21:33
Et, au cas ou, pour parcourir toute la liste :
For Each personne as System.Collections.Generic.KeyValuePair(Of String, Personne) In personnes
  Console.WriteLine("Nom {0} ; Prénom {1} ; Age = {2}", personne.Key, personne.Value.Prenom, personne.Value.Age)
Next
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
12 mars 2011 à 21:56
Merci beaucoup foliv57 pour cette derniere proposition.....Il va falloir que j'analyse le comportement de cette methode plus en détail, ca à l'air trés simple et efficace....c'est peut-être exactement ce que je cherchais.....
Avec tout mes remerciements....
0
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 1
12 mars 2011 à 22:05
Idem ... Tres ingenieux comme manière de faire
Merci beaucoup pour ton Post.
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
12 mars 2011 à 23:18
Désolé, je pensais en avoir fini avec ce post mais j'en encore une question.
Je m'apercois que l'on ne pas deserializer une structure (ou du moins trés diffilement)...est ce que la solution proposé par Foliv57 peut me permettre de serializer/deserializer facilement ?
Par avance je vous remercie beaucoup.
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
13 mars 2011 à 10:21
Bonjour,
J'ai effectué des essais avec la méthode de Foliv57, je rencontre 2 problèmes :

1 - Pour assigner une valeur du style :
personnes("Durant").Age = 30 'Ca ne marche pas

2 - Pour sérialiser les données
Avec la méthode de Foliv57 ou en utilisant des structures classique, lorsque je veux déserializer j'obtiens un message : Le cast n'est pas valide ! Ca veux dire quoi et comment régler ce problème...

PS : J'aimerais beaucoup pouvoir structurer mes donner comme le propose Foliv57....aprés tous les essais que j'ai fait ca me parait être une méthode trés efficace si j'arrive à résoudre ces 2 points.....
Merci beaucoup pour votre aide....
0
foliv57 Messages postés 420 Date d'inscription vendredi 17 novembre 2006 Statut Membre Dernière intervention 15 juillet 2014 9
13 mars 2011 à 11:35
1 - Pour assigner une valeur du style :
personnes("Durant").Age = 30 'Ca ne marche pas


Désolé, j'ai écrit l'exemple sans visual studio et j'avais completement oublié qu'on ne pouvait pu affecter un membre d'une structure dans une collection, donc qu'il faut réaffecter toute la structure ex :
personnes("Durant") = New Personne(personnes("Durant").Prenom, 30)


Mais du coup cela rend la solution disgracieuse.

J'ai réinstallé un VB express, je vous prépare un exemple qui tien la route avec la sérialisation.
0
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 1
13 mars 2011 à 12:19
Bonjour a vous deux,
En attendant, cette solution marche mais est loin d'être propre

Dim P As Personne = personnes.Item("Durant")
P.Age = 30
personnes.Item("Durant") = P

Il y a surement mieux ....
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
13 mars 2011 à 14:03
Merci CGSI3 et Foliv57....
Je ne pourrais tester que ce soir c'est ta proposition Foliv57 à l'air de vraiment tenir la route...Je te remercie infiniment pour tes efforts. Par contre à Priori tu dezerialise les données pour les affichées sur la console, est ce que on peux deserializer pour recharger les données dans la collection 'Personnes' ?
Merci beaucoup si vous pouvez répondre à cette derniere petite question...j'espère.
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
13 mars 2011 à 14:54
Merci beaucoup Foliv57, Tous ce ci me parait excellent, j'essaye tous ca dès ce soir. Si tous fonctionne comme prevus je pense que c'est un modèle de structuration des données que je généraliserais quasiment dans toutes mon appli....Merci beaucoup pour votre aide.
0
BasicZx81 Messages postés 140 Date d'inscription samedi 5 mars 2011 Statut Membre Dernière intervention 13 août 2013
13 mars 2011 à 18:22
Bonsoir à tous, le code de Foliv57 que je remercie beaucoup fonctionne parfaitement, pour ceux que ca interresse je rajouterais 2 instructions qui pourront être utile à certains d'entres vous ou au débutant.

'Indique le nombre de personne
MsgBox(personnes.Count)

'Controle obligatoire avant création d'une personne pour ne pas générer une erreur :
If personnes.ContainsKey("Dupond") Then MsgBox("la Personne existe déja ")

Cordialement.
0
CGSI3 Messages postés 416 Date d'inscription vendredi 22 février 2008 Statut Membre Dernière intervention 7 janvier 2018 1
13 mars 2011 à 19:24
Grand merci a vous deux,
très efficace comme code !
Bonne soirée
CGSI3
0
Rejoignez-nous