Gestion de librairie Dictionnary

Bonjour forum,

J'ai pu évoluer sur un environnement VBA où je pouvais créer un dictionnaire avec la ligne de code:

 Dim MyDico as dictionary
                set MyDico as new dictionary

ou encore pour une fonction

 Public function trie( MyDico as Dictionary) as Dictionary
                End sub

J'ai chargé la librairie Microsoft Offie Runtime mais il ne reconnait pas cet écriture. Il affiche: Utilisateur a utilisé un style non défini.

Quelqu'un a t il une idée?

Merci d'avance.

Bonjour,

je ne vois pas bien le rapport entre le message d'erreur et tes lignes (?.!?)

Ceci dit déclare tes dictionary plutôt comme ça :

    Dim dict
    Set dict = CreateObject("Scripting.Dictionary")

pour ne pas être tributaire de la version présente sur le pc.

Et si la fonction te pose toujours des problèmes laisse en Variant.

eric

Bonjour Eric,

Oui, je suis d'accord avec ta proposition. C'est de la sorte que je contourne l'autre façon de déclarer qui utilise dictement le mot "dictionary".

Pour la fonction, je demandais un contournement parce que scripting.dictionary ne fonctionne pas. Je n'ai pas pensé en style variant. Je vais tester.

Merci.

Bonjour Eric,

Le type variant modifie la nature de mon élément de sortie. Ma ligne de code:

 MyDico = FonctionTrieDico(MyDico)  

plante par ce que l'élément de sortie est de type variant alors que MyDico est de type dictionary (même si on est passé par le scripting.dictionary).

Il semble qu'il y ait une bibliothèque spécifique à charger en plus de la biblio: "MS Office Runtime " pour le forcer à accepter les déclaration directe en

Dim Dico as Dictionary

Si tu déclares le dict comme je te l'ai indiqué plus besoin de se soucier des librairies.

Tu ne peux pas trier un dictionary directement.

On peut même se demander si tu as bien fait de choisir ça vu que son but est d'obtenir directement une valeur à partir d'une autre et pour cet usage nul besoin qu'il soit trié.

Il faut mettre items et keys dans 2 variables tableaux, faire ton tri sur l'un ou l'autre en faisant suivre sur le second, et reconstruire un dictionary.

Public function trie( MyDico as object) as object
dim it, ke
it=MyDico.items
ke=MyDico.keys
' trier
'...
Set trie = CreateObject("Scripting.Dictionary") ' ton nom de fonction
' construire le nouveau dico avec une boucle et trie.add clé, item
'...
End Function

Tu as un autre objet (ArrayList) qui a la méthode .Sort et permet un tri immédiat.

http://analystcave.com/excel-vba-dictionary-arrays-and-other-data-structures/#The_VBA_ArrayList_object

Sur cet exemple faire arrList.Sort

Ok. Je vais tester ta proposition.

Je souhaitais utiliser un bout de code qui fonctionne bien normalement. C'est celui là que je cherchais à utiliser. Je te le partage, tu me diras ce que t'en pense. Je vais voir comment l'adapter de mon côté si possible.

Public Function TrierDictionnaireParCle(Dico As Dictionary) As Dictionary
'par Excel-Malin.com ( http://excel-malin.com )

'Fonction VBA qui trie l'Object Dictionnary par clé
'ce code nécessite que la référence "Microsoft Scripting Runtime" soit activée

On Error GoTo ErreurTri

     'définition des variables
     'Dim Dict As Scripting.Dictionary
     Dim DicoTemporaire As Scripting.Dictionary
     Dim PaireTemporaire As Variant
     Dim ArrayTemporaire() As Variant
     Dim OrdreTemporaire As Variant
     'Dim Txt As String
     Dim i As Long
     Dim j As Long

     'Allocation de l'espace de mémoire pour un Array dynamique
     ReDim ArrayTemporaire(0 To Dico.Count - 1)

    ' 1) Remplissage de l'Array avec les valeurs du Dictionnaire non-trié
     For i = 0 To Dico.Count - 1
        ArrayTemporaire(i) = Dico.Keys(i)
     Next i

     ' 2) Tri de l'Array
     For i = LBound(ArrayTemporaire) To UBound(ArrayTemporaire) - 1
         For j = i + 1 To UBound(ArrayTemporaire)
             If ArrayTemporaire(i) > ArrayTemporaire(j) Then
                 OrdreTemporaire = ArrayTemporaire(j)
                 ArrayTemporaire(j) = ArrayTemporaire(i)
                 ArrayTemporaire(i) = OrdreTemporaire
             End If
         Next j
     Next i

    ' 3) Création d'un nouveau Dictionnaire (Temporaire)
    Set DicoTemporaire = New Dictionary

     ' 4) Ajout des valeurs triées dans le Dictionnaire  temporaire(à partir de l'Array créé précédemment)
     For i = LBound(ArrayTemporaire) To UBound(ArrayTemporaire)
         PaireTemporaire = ArrayTemporaire(i)
         DicoTemporaire.Add Key:=PaireTemporaire, Item:=Dico.Item(PaireTemporaire)
     Next i

     ' 5) Renvoi du Dictionnaire trié
     Set TrierDictionnaireParCle = DicoTemporaire
Exit Function

ErreurTri:
Set TrierDictionnaireParCle = Nothing

End Function

oui, c'est exactement ça.

Tu as juste à remplacer la déclaration et l'initialistaion du dico par ce que je t'ai indiqué.

Merci de ton retour.

C'est bon au niveau de la sortie de fonction. L'objet en sortie est bien un dictionnaire, là pas de problème.

Seulement, quand je trie le dictionnaire avec

set MyDico = trie(MyDico)

et que dans la suite du programme j'appelle dans un

for each key in MyDico.keys

, le programme plante là encore.

Est ce à cause du type object en paramètre de fonction trie selon ta préconisation?

 Public function trie( Dico as object)  as object
          set trie=createobject("Scripting.Dictionary")

Je constate que le programme compile bien sans l'appelle de trie. Mais dès que je l'appelle, il y a un problème de compilation.


Et le problème de compilation n'a pas lieu sur la fonction trie ni sur aucune ligne où elle apparait. Je ne peux juste plus appeler les éléments de MyDico par MyDico.keys.

Un peu étrange tout pour moi, je te l'avoue.

Si tu donnais les messages d'erreurs au lieu de "ça plante" tu ne crois pas que ça aiderait ?

Dans for each key in MyDico.keys key doit être variant

For i = 0 To UBound(AA) - 1
                                If AA(i) <> BB(i) And AA(i) <> "" Then
                                       D = AA(i)
                                       If Not MonDico2.exists(D) Then MonDico2.Add D, cle
                                End If
                            Next i

Sur la ligne If not... Erreur d'exécution 91: "Variable objet ou varable de bloc with non définie"

Bonsoir,

Avec un VRAI tri

Sub TriDico()
  Set f = Sheets("BD")
  Set d1 = CreateObject("Scripting.Dictionary")
  a = f.Range("A2:A" & f.[A65000].End(xlUp).Row)  ' tableau a(n,1) pour rapidité
  For i = LBound(a) To UBound(a)
   If a(i, 1) <> "" Then d1(a(i, 1)) = ""
  Next i
  DicoTri d1
  f.[C2].Resize(d1.Count) = Application.Transpose(d1.keys)
End Sub

Sub DicoTri(dico)
  Tbl = dico.keys
  Tri Tbl, LBound(Tbl), UBound(Tbl)
  dico.RemoveAll
  For i = LBound(Tbl) To UBound(Tbl)
    dico(Tbl(i)) = ""
  Next i
End Sub

Sub Tri(a, gauc, droi)          ' Quick sort
 ref = a((gauc + droi) \ 2)
 g = gauc: d = droi
 Do
     Do While a(g) < ref: g = g + 1: Loop
     Do While ref < a(d): d = d - 1: Loop
     If g <= d Then
       temp = a(g): a(g) = a(d): a(d) = temp
       g = g + 1: d = d - 1
     End If
 Loop While g <= d
 If g < droi Then Call Tri(a, g, droi)
 If gauc < d Then Call Tri(a, gauc, d)
End Sub

Ceuzin

33dicotri.zip (25.22 Ko)
If Not MonDico2.exists(D) Then MonDico2.Add D, cle

ta fonction s'appelle MonDico2 ???

Le dict à utiliser doit porter le nom de la fonction, je te l'avais mis en commentaire.

eric

Formidable, le tri est dichtomique à la lecture du code. Je ne le connaisse qu'en C.

Cela dit, quand je lance ton bouton dans le fichier excel, il s'affiche en MsgBOx: !argument ou appel de procédure incorrect dans le Sub TriDico.

Pour ce qui est de toon précédent message

eriiic a écrit :
If Not MonDico2.exists(D) Then MonDico2.Add D, cle

ta fonction s'appelle MonDico2 ???

Le dict à utiliser doit porter le nom de la fonction, je te l'avais mis en commentaire.

eric

Je t'avoue que je n'ai pas compris le principe, désolé d'être si débutant. La fonction ne fonction pas comme les autre fonction du genre: set Dico =TrieDico( Dico ) ? Pourquoi le dictionnaire doit il porter le même nom que la fonction?


Je viens de me relire, ce que je n'ai pas fait tout à l'heure. Navré des diverses fautes d'écriture.

Je veux dire, plus lisiblement cette fois, je n'ai pas compris la raison pour laquelle le Dico doit porter le nom de la fonction systématiquement.

Bonjour,

parce que tu veux que ta fonction retourne le dico.

Et tu vois bien que c'est ce que fait la fonction que tu as collé après :

    Set TrierDictionnaireParCle = DicoTemporaire
Exit Function

Le mieux est d'appliquer bêtement et de tester.

eric

Bonjour Eric,

Merci beaucoup du retour.

Peut être une dernière question avant de clore le sujet, quand on supprime des éléments d'un dictionnaire ( pas forcéments aux extrémités du dico), la position des clés dictionnaire est elle recalculée automatiquement ? Ce qui implique que a taille diminue aussi du nombre d'éléments retirés? Ou le dictionnaire reste tel quel, avec des cases vides, sans redimensionnement automatique.

Merci encore du précieux temps que tu consacres à donner en réponse à mes interrogations.

Pareil.

Tu testes et tu reviens nous dire

Sert-toi de la fenêtre Espions. Tu sélectionnes une variable ou une expression dans le code que tu fais glisser dans cette fenêtre.

Par exemple avec monDic. Dans la fenêtre Espions tu ajoutes au bout .keys ou .items et tu peux contrôler

Entendu. Je ferai et te reviendrai à ce moment là. Merci encore.

Bonsoir,

  • Tri dictionnaire Keys/Valeurs ou Tri Valeurs/Keys sous forme de procédure
  • Tri dictionnaire Keys/Valeurs ou Tri Valeurs/Keys sous forme de fonction
Option Compare Text
Sub TriDicoKeysValeurs()
  Set f = Sheets("BD")
  Dim d1 As New Dictionary
  Dim d2 As New Dictionary
  d1.CompareMode = vbTextCompare
  a = f.Range("A2:B" & f.[A65000].End(xlUp).Row)  ' tableau a(n,2) pour rapidité
  For i = LBound(a) To UBound(a)
   If a(i, 1) <> "" Then d1(a(i, 1)) = a(i, 2)
  Next i
  Set d2 = DicoTriKeysVal(d1, 1)  ' tri par clés
  f.[d2].Resize(d2.Count) = Application.Transpose(d2.keys)
  f.[e2].Resize(d2.Count) = Application.Transpose(d2.items)
End Sub

Function DicoTriKeysVal(dico, colTri) As Dictionary
  Dim d As New Dictionary
  Dim Tbl(): ReDim Tbl(1 To dico.Count, 1 To 2)
  i = 0
  For Each c In dico.keys
    i = i + 1
    Tbl(i, 1) = c: Tbl(i, 2) = dico(c)
  Next c
  Tri Tbl, LBound(Tbl), UBound(Tbl), colTri
  For i = LBound(Tbl) To UBound(Tbl)
    d(Tbl(i, 1)) = Tbl(i, 2)
  Next i
  Set DicoTriKeysVal = d
End Function

Ceuzin

Bonjour Ceuzin,

Merci beaucoup je pour na proposition que je vais tester. Je note que vous utilisez la déclaration directe Dim d1 as new dictionary sans passer par le scripting comme je demandais plus tôt.

C'est un détail mais qui simplifie l'écriture à mon sens. Comment charger cette librairie pour imposer le type dictionary comme les autres type "collection", "variant","string" etc. ..?

Merci d'avance.

Bonjour,

C'est un détail mais qui simplifie l'écriture à mon sens.

Là tu retournes à la case départ où il te faudra intervenir pour chaque version différente d'excel.

Fait une recherche sur le late binding, j'abandonne de t'expliquer moi.

eric

Rechercher des sujets similaires à "gestion librairie dictionnary"