je suis l’hérétique de service, J’ai créé un dictionnaire avec doublons !
Je souhaite à partir de ce dictionnaire créer un dictionnaire sans doublon
C’est pour le fun je sais le créer à partir d’une plage
Donc voici le code qui ne fonctionne pas
Sub nefonctionnepas() '
For Each c In DavecDoublons.Keys
DsansDoublon(c.Value) = ""
MsgBox c
Next c
End Sub
pièce jointe
C’est surtout pour faire marcher ma boîte à malices et éviter qu’elle ne se grippe ! Et je cherche à comprendre le fonctionnement d'un dictionnaire.
Avec mes sincères remerciements anticipés .
Goufra
Bonjour
le fonctionnement d'un dictionnaire est on ne peut plus simple
un dictionnaire a des clés et des items (valeur : numerique,string ou même object)
quand on ajoute un element dans le dictionnaire on le fait par sa clé
exemple
dictionnaire("toto")="ce que tu veux"
maintenant si je fait
dictionnaire("toto")="autre chose"
en fait ici on a changé la valeur de l'item du dictionnaire pas sa clé il n'y a donc toujours q'une seule clé ce qui veux dire pas de doublons
le dictionnaire a des méthode comme par exemple la fonction exists
if not dictionnaire.exists("toto") then dictionnaire("toto")="trucbidule"
avec cette méthode cela permet de ne plus y toucher dans une boucle par exemple
oserais-je dire qu'il existe deux autres objects plus ancien mais encore fonctionels dans windows
l'object (arraylist)
et
l'object("sortedlist")
qui ont d'autre fonctions et méthode intégrées tel que le tri dans un ordre ainsi que le deplacement dans la hiérachie etc..etc..
pour le dictionnaire
on peut le transformer par la suite en deux array distincts et exploitables
macolonneclé=application.transpose(dictionnaire.keys)
macolonnevaleur=application.transpose(dictionnaire.items)
ces deux variable sont des array contenant les valeurs et clé (sans doublons bien sur )
pour en apprendre un peu plus et mettre tout cela en pratique je te renvoie vers une page de notre regretté Jacques Boisgontier
je pense qu'il y a suffisamment d'exemples et mise en pratique pour maitriser ou apprendre à maitriser le dictionnaire
Par l'implémentation de l'objet "Dictionary", une clef est unique.
Donc construire un "Dictionary "avec plusieurs clefs identiques n'est pas possible.
Votre "Dictionary" est forcément sans doublon. C'est donc la conclusion que vous tirez du résultat de votre code qui est fausse. Vous n'avez pas construit de "Dictionary" avec doublons.
Le classeur que vous avez fourni est un peu fouillis.
J'ai considéré votre procédure : Dictionnaire3()
Quand on construit un dictionary, il faut s'interroger sur ce qu'est la clef et ce qu'est l'item associé.
Votre dictionary doit comporter en clef les valeurs de la colonne 2 du tableau structuré 'Tableau1" et comme élément associé les valeurs de la colonne 3 du tableau structuré "Tableau1".
Vous remarquerez que j'ai bien mentionné valeur et pas cellules.
Considérons la ligne d'insertion dans votre dictionary : D.Add ActiveCell(i, 2), ActiveCell(i, 3).Value
La clef est ActiveCell(i, 2). ActiveCell(i, 2) n'est pas une valeur mais un objet Range (cellule, monoplage ou multiplage). En l'occurrence ici c'est une cellule et non pas la valeur de la cellule.
Au sein de la boucle i, quand i varie, ActiveCell(i, 2) sera à chaque fois une cellule différente de la précédente (i-1) et différente de la cellule suivante (i+1). Et ceci est vrai quelque soient les valeurs de ces cellules (identiques ou non).
Donc vous remplissez votre dictionnaire avec des clefs toutes différentes (autant que de cellules dans la colonne 2 de votre tableau). Votre dictionary ne comporte aucun doublon au niveau des clefs.
Si vous remplacez votre ligne de code par : D.Add ActiveCell(i, 2).Value, ActiveCell(i, 3).Value,
VBA vous avertira de la présence de doublon car la clef est la valeur des cellules et non pas l'objet cellule lui-même.
Remarque : l'erreur peut aussi être induite par le fait que la valeur par défaut d'un range cellule est la valeur de la cellule et souvent on confond les deux.
La plupart du temps quand on écrit : X=Cells(1,1), X va contenir la valeur de la cellule X (ça marche aussi pour un range monoplage). Car VBA sait que le signe = correspond à la valeur. Si on considère l'objet range lui-même, on écrira Set X=Cells(1,1), VBA sait alors que l'emploi du SET correspond à l'objet range et non à la valeur du range.
Mais l'objet dictionary accepte comme clef différents types de variables.
Quand on insère une clef X dans un dictionary, la clef sera du type de X.
Si on lui donne comme clef un range, il considérera que la clef est le range et non pas sa valeur.
Concernant votre procédure, vous avez déjà le tableau des valeurs : T1 = Range("tableau1")
Inutile d'aller sur la feuille de calcul pour lire les cellules, les sélectionner, etc (en plus cela prend du temps d'exécution).
Voir module1. Cliquez sur le bouton Hop!
Code dans module1 :
VB:
Option Explicit
Dim D As New Scripting.Dictionary
Sub Dictionnaire3()
Dim T, i&
D.RemoveAll 'on vide le dictionary
T = Range("tableau1") 'on lit les valeurs du tableau structuré "tableau1"
For i = 1 To UBound(T) 'boucle sur les lignes de T
If Not D.Exists(T(i, 2)) Then D.Add T(i, 2), T(i, 3)
Next i
Range(Range("G7"), Range("G7").End(xlDown)).Resize(, 2).Clear 'on efface les anciens résultats
Range("G7").Resize(D.Count, 1) = Application.Transpose(D.Keys) 'les clefs
Range("H7").Resize(D.Count, 1) = Application.Transpose(D.Items) 'les items
End Sub
Par l'implémentation de l'objet "Dictionary", une clef est unique.
Donc construire un "Dictionary "avec plusieurs clefs identiques n'est pas possible.
Votre "Dictionary" est forcément sans doublon. C'est donc la conclusion que vous tirez du résultat de votre code qui est fausse. Vous n'avez pas construit de "Dictionary" avec doublons.
Le classeur que vous avez fourni est un peu fouillis.
J'ai considéré votre procédure : Dictionnaire3()
Quand on construit un dictionary, il faut s'interroger sur ce qu'est la clef et ce qu'est l'item associé.
Votre dictionary doit comporter en clef les valeurs de la colonne 2 du tableau structuré 'Tableau1" et comme élément associé les valeurs de la colonne 3 du tableau structuré "Tableau1".
Vous remarquerez que j'ai bien mentionné valeur et pas cellules.
Considérons la ligne d'insertion dans votre dictionary : D.Add ActiveCell(i, 2), ActiveCell(i, 3).Value
La clef est ActiveCell(i, 2). ActiveCell(i, 2) n'est pas une valeur mais un objet Range (cellule, monoplage ou multiplage). En l'occurrence ici c'est une cellule et non pas la valeur de la cellule.
Au sein de la boucle i, quand i varie, ActiveCell(i, 2) sera à chaque fois une cellule différente de la précédente (i-1) et différente de la cellule suivante (i+1). Et ceci est vrai quelque doit les valeurs de ces cellules (identiques ou non).
Donc vous remplissez votre dictionnaire avec des clefs toutes différentes (autant que de cellules dans la colonne 2 de votre tableau). Votre dictionary ne comporte aucun doublon au niveau des clefs.
Si vous remplacez votre ligne de code par : D.Add ActiveCell(i, 2).Value, ActiveCell(i, 3).Value,
VBA vous avertira de la présence de doublon car la clef est la valeur des cellules et non pas l'objet cellule lui-même.
Remarque : l'erreur peut aussi être induite par le fait que la valeur par défaut d'un range cellule est la valeur de la cellule et souvent on confond les deux.
La plupart du temps quand on écrit : X=Cells(1,1), X va contenir la valeur de la cellule X (ça marche aussi pour un range monoplage). Car VBA sait que le signe = correspond à la valeur. Si on considère l'objet range lui-même, on écrira Set X=Cells(1,1), VBA sait alors que l'emploi du SET correspond à l'objet range et non à la valeur du range.
Mais l'objet dictionary accepte comme clef différents types de variables.
Quand on insère une clef X dans un dictionary, la clef sera du type de X.
Si on lui donne comme clef un range, il considérera que la clef est le range et non pas sa valeur.
Concernant votre procédure, vous avez déjà le tableau des valeurs : T1 = Range("tableau1")
Inutile d'aller sur la feuille de calcul pour lire les cellules, les sélectionner, etc (en plus cela prend du temps d'exécution).
Voir module1. Cliquez sur le bouton Hop!
Code dans module1 :
VB:
Option Explicit
Dim D As New Scripting.Dictionary
Sub Dictionnaire3()
Dim T, i&
D.RemoveAll 'on vide le dictionary
T = Range("tableau1") 'on lit les valeurs du tableau structuré "tableau1"
For i = 1 To UBound(T) 'boucle sur les lignes de T
If Not D.Exists(T(i, 2)) Then D.Add T(i, 2), T(i, 3)
Next i
Range(Range("G7"), Range("G7").End(xlDown)).Resize(, 2).Clear 'on efface les anciens résultats
Range("G7").Resize(D.Count, 1) = Application.Transpose(D.Keys) 'les clefs
Range("H7").Resize(D.Count, 1) = Application.Transpose(D.Items) 'les items
End Sub
Dans ce cas, la clef est la valeur de la cellule c et l'élément (Item) associé à la clef est la chaine de caractère vide notée ""
"toto" représente la chaine de caractère toto (4 caractères)
"t" représente la chaine de caractère t (1 caractère)
"" représente la chaine de caractère vide (0 caractère)
On utilise cela souvent pour trouver les valeurs uniques.
Exemple : Trouver les valeurs uniques des cellules de la plage A1 à A100.
Les valeurs uniques sont compris dans dico.keys, le nombre de valeur unique est dico.Count.
VB:
Sub test()
Dim i As Long, dico As Object
Set dico = CreateObject("scripting.dictionary")
For i = 1 To 100
If Cells(i, "a") <> "" Then dico(Cells(i, "a").Value) = ""
Next i
Columns("c:c").ClearContents
If dico.Count > 0 Then Range("c1").Resize(dico.Count) = Application.Transpose(dico.keys)
End Sub
Quand on utilise la notation dico(clefx) = itemx, que fait le dictionary ?
si la clef existe déjà, il remplace l'ancien item de la clef clefx par l'item itemx.
si la clef n'existe pas, il crée l’élément de clef clefx et ensuite seulement lui attribue l'item itemx
Ce code je l'ai pris sur le site de j.gonthier. C'est le premier code développé.
For Each c In plage
DsansDoublon(c.Value) = ""
Next c
Je suis navré mais je dois avoir atteint mon plafond de verre, je ne comprends pas votre explication.
Une autre instruction que je ne comprends pas.
Range(Range("G7"), Range("G7").End(xlDown)).Resize(, 2).Clear
End(xldown)
Si 10 inscriptions, seules les 10 lignes sont effacées et non celles servies dessous. Il n'efface donc pas jusqu'à la fin des deux colonnes concernées.
Je vous remercie pour votre patience
bien cordialement
Goufra
Un dictionary (qu'on nommera dic) est une structure qui possède des clefs et des éléments. A chaque clef est associé un élément (Item). Au sein du dictionary, il ne peut y avoir deux fois la même clef.
Pour mettre un élément (clef + item associé) dans un dictionary, on peut utiliser deux manières de faire.
La première est (la plus logique selon moi) :
dic.add clef, item ( ex: dic.add "Voiture","Citroën" )
Si la clef "Voiture" est déjà présente, alors dic.add "Voiture","Citroën" aboutira à une erreur dans le programme.
En général, on écrit donc :
if not dic.exists("Voiture") then dic.add "Voiture","Citroën" (on évite ainsi l'erreur de vouloir ajouter une clef déjà existante)
La seconde est :
dic(clef)=item ( ex : dic("Voiture")="Citroën" )
Si la clef existe, la méthode add va rechercher l'enregistrement de clef "Voiture" et place dans l'Item correspondant la nouvelle valeur "Citroën" (cela écrase la précédente valeur associée à la clef "Voiture")
Si la clef n'existe pas, alors cette méthode crée un enregistrement de clef "Voiture" et lui associé l'élément "Citroën".
Cette seconde méthode ne provoque pas d'erreur si la clef existe déjà.
Merci
Je me suis mal exprimé. J'avais compris votre démonstration ci-dessus.
mais dans le 1er code du site de j.b :
For Each c In plage
DsansDoublon(c.Value) = ""
Next c
je reviens à mes moutons... pour essayer de comprendre = ""
Je vous offre volontiers un café "virtuel" et toute ma reconnaissance, assurément.
Bien cordialement
JC Goufra
Ce code permet de construire une liste de clefs uniques (au sein du dictionary).
Ce qui nous intéresse ici, c'est la liste des clefs au sein du dictionary et aucunement les valeurs associées aux clefs dont on se fiche royalement.
Donc on pourrait écrire DsansDoublon(c.Value) = "" ou DsansDoublon(c.Value) = 123456 ou DsansDoublon(c.Value) = "N'importe quoi" ou encore DsansDoublon(c.Value) = -1. Ce qui nous importe c'est la liste des clefs. Qu'on leur affecte un nombre, un texte ou la chaine de caractère vide, on n'en a cure. L'important c'est de mettre les clefs dans le dictionary.
Admettons que la plage comporte les valeurs (1, "toto", 456, "toto", 1)
Passage n°1 dans la boucle : on fait DsansDoublon(1)=-1. La clef n'existe pas dans dictionary, elle est donc créée avec comme item associé -1. Le dictionary contient donc l'ensemble (clef, item) égal à (1, -1)
Passage n°2 dans la boucle : on fait DsansDoublon("toto")=-1.La clef n'existe pas dans dictionary, elle est donc créée avec comme item associé -1. Le dictionary contient donc les ensembles (clef, item) égal à (1, -1) et ("toto",-1)
Passage n°3 dans la boucle : on fait DsansDoublon(456)=-1.La clef n'existe pas dans dictionary, elle est donc créée avec comme item associé -1. Le dictionary contient donc les ensembles (clef, item) égal à (1, -1) et ("toto",-1) et (456,-1)
Passage n°4 dans la boucle : on fait DsansDoublon("toto")=-1. La clef "Toto" existe déjà donc le dictionary ne la crée pas mais va remplacer l'item existant pour la clef "toto" par le nouvel item -1 (qui est était déjà -1 mais ça on s'en fiche!). Le dictionary contient donc les ensembles (clef, item) égal à (1, -1) et ("toto",-1) et (456,-1). Rien n'a changé.
Passage n°5 dans la boucle : on fait DsansDoublon(1)=-1. La clef 1 existe déjà donc le dictionary ne la crée pas mais va remplacer l'item existant pour la clef 1 par le nouvel item -1 (qui est était déjà -1 mais ça on s'en fiche! encore une fois). Le dictionary contient donc les ensembles (clef, item) égal à (1, -1) et ("toto",-1) et (456,-1). Rien n'a changé.
Donc à la fin de la boucle, le dictionnaire contient les ensembles (clef, item) égaux à (1, -1) et ("toto",-1) et (456,-1).
la liste des clefs est (1, "toto", 456) et la liste des items associés est(-1, -1, -1).
On trouve donc bien 3 valeurs uniques (DsansDoublon.count) et la liste de ces valeurs uniques est dans DsansDoublon.Keys.
On peut remplacer dans la boucle la valeur -1 par "". On serait arrivé au même résultat pour DsansDoublon.Keys.
Merci
Suis-je bête !
Ce qui me trouble:
j'obtiens un dictionnaire sans avoir eu besoin de mettre " if not Dsansdoublon exists"
Parfois je suis obligé de mentionner en début de code on error resume next, pour continuer.
Je suis vraiment navré de mon niveau d'incompréhension
Merci CP4
Bien cordialement