Une fonction qui "ordonne" les clé d'un dictionnaire

Résolu/Fermé
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 - 10 juil. 2015 à 17:08
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 - 17 juil. 2015 à 19:41
Bonjour.
Je travail sous VBA Excel.
J'utilise un dictionnaire pour obtenir une liste sans doublons.
J'ai créé mon dico ainsi :
Set Mon_Dico = CreateObject("Scripting.Dictionary")

Puis j'ai remplis mon dico :
TABLEAU = Sheets("Feuil1").Range("A2", "A100")
For I = 1 To UBound(TABLEAU, 1)
    Mon_Dico(Tableau_SITE(I, 1)) = ""    
Next I


Maintenant je souhaite pouvoir ordonner les clés de mon dictionnaire :

Je suis en train de créer une fonction "Ordonne_Dico" ... mais je n'y arrive pas.

J'appelle ma fonction :
Mon_Dico = Ordonne_Dico(Mon_Dico)


Et j'ai crée ma fonction :

Function Ordonne_Dico(Dico) ' Ordonne le dictionnaire par sa key
ListeCle = Dico.Keys
ListeElement = Dico.Items

    For I = 0 To Dico.Count - 2
 
        For k = I + 1 To Dico.Count - 1
 
            If ListeCle(I) > ListeCle(k) Then
 
                Tempo_Cle = ListeCle(k)
                Tempo_Element = ListeElement(k)
 
                ListeElement(k) = ListeElement(I)
                ListeCle(k) = ListeCle(I)
 
                ListeCle(I) = Tempo_Cle
                ListeElement(I) = Tempo2_Element
 
            End If
 
        Next k
 
    Next I

Set Ordonne_Dico = CreateObject("Scripting.Dictionary")
Ordonne_Dico.Keys = ListeCle
Ordonne_Dico.Items = ListeElement

End Function


ça ne marche pas.
Je ne parviens pas à récupérer mon dictionnaire ordonné en fin de fonction !!
Quelqu'un aurait déjà fait quelque-chose de similaire ??


Merci
A voir également:

6 réponses

f894009 Messages postés 17185 Date d'inscription dimanche 25 novembre 2007 Statut Membre Dernière intervention 15 avril 2024 1 701
10 juil. 2015 à 17:31
0
ThauTheme Messages postés 1442 Date d'inscription mardi 21 octobre 2014 Statut Membre Dernière intervention 29 juillet 2022 160
10 juil. 2015 à 17:34
Bonjour WireLess, bonjour le forum,

Honteusement pompé sur le site de Jacques Boisgontier (tant pis si je me fait engueuler pour ce genre de citation) :

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
      tmp = a(g): a(g) = a(d): a(d) = tmp
      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


à la fin de la boucle du dictionnaire tu écris :
Temp = Mon_Dico.Keys
Call Tri(Temp,Lbound(TMP,1),Ubound(TMP,1))
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
15 juil. 2015 à 15:16
Bon ...
J'en arrive à la conclusion qu'on ne peut pas utiliser une fonction pour ordonner un dictionnaire ...

C'est dommage parce que j'ai plusieurs dictionnaire à ordonner ... et de passer par une fonction, il me semblait que c'était le moyen le plus propre.

Mais quand même ... si quelqu'un a une idée magique ...
Mon problème dans le code ci-dessous, c'est que la ligne 27 de mon code ... rappel le début de ma fonction ... (et la boule est bouclé pour ainsi dire.)

Function Ordonne_Dico(Dico) As Variant ' Ordonne le dictionnaire par sa key
ListeCle = Dico.Keys
ListeElement = Dico.Items
  
    For I = 0 To Dico.Count - 2
 
        For k = I + 1 To Dico.Count - 1
 
            If ListeCle(I) > ListeCle(k) Then
 
                Tempo_Cle = ListeCle(k)
                Tempo_Element = ListeElement(k)
 
                ListeElement(k) = ListeElement(I)
                ListeCle(k) = ListeCle(I)
 
                ListeCle(I) = Tempo_Cle
                ListeElement(I) = Tempo2_Element
 
            End If
 
        Next k
 
    Next I

For I = 1 To UBound(ListeCle, 1)
    Ordonne_Dico(ListeCle(I)) = ""
Next I

End Function


Merci tout de même à tout ceux qui ont répondu à mon sujet (Thautheme ; f894009 ).
Si personne n'a d'idées magique ... je clôturerais le sujet .
Merci
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
Modifié par wire less le 15/07/2015 à 15:42
Je ne comprend pas ThauTheme.

A la fin de ton script
Temp = Mon_Dico.Keys
Call Tri(Temp,Lbound(Temp,1),Ubound(Temp,1))

Je ne peux pas récupérer Temp trié à partir d'un "sub" ??
Il faut forcement que je passe par une fonction ?? non ???
0
ThauTheme Messages postés 1442 Date d'inscription mardi 21 octobre 2014 Statut Membre Dernière intervention 29 juillet 2022 160 > wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018
15 juil. 2015 à 15:49
Ben le sub c'est TRI(a, gauc, droi) et c'est pas une fonction... Il te suffit de lancer le Sub à chaque dictionnaire... C'est moi qui ne comprends pas où est le problème pour toi ?
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5 > ThauTheme Messages postés 1442 Date d'inscription mardi 21 octobre 2014 Statut Membre Dernière intervention 29 juillet 2022
15 juil. 2015 à 16:47
:-/
Ben ... mon dico sera bien trié, mais ce dictionnaire n'existera qu'à l'intérieur de mon sub TRI(a, gauc, droi) !!
Il n'existera pas à l'extérieur de ce "sub" !
Si je veux le faire remonter dans mon sub, il faut soit que j'utilise une fonction, soit que je déclare mon dico en variable global :-/ (ce qui est impossible pour les dico dans les user form :-/ )
Voilou mon problème !!
A moins que je ne sois complètement fou !!
0
ThauTheme Messages postés 1442 Date d'inscription mardi 21 octobre 2014 Statut Membre Dernière intervention 29 juillet 2022 160
15 juil. 2015 à 17:07
Ben non ! Ton dico est définit et déclaré dans ton premier sub... La fonction Tri ne sert qu'à trier un tableau et un dictionnaire est un tableau !... C'est pour cela que je te disais d'ajouter, après la création de ton dictionnaire, les lignes qui vont le trier. Si je reprends ton exemple ça donne :

Sub Macro1()
Set Mon_Dico = CreateObject("Scripting.Dictionary")
TABLEAU = Sheets("Feuil1").Range("A2", "A100")
For I = 1 To UBound(TABLEAU, 1)
    Mon_Dico(Tableau_SITE(I, 1)) = ""
Next I
'lignes pour trier
TEMP = Mon_Dico.keys
Call Tri(TEMP, LBound(TEMP), UBound(TEMP))
'ligne pour utiliser le tri
Me.listbox1.List = TEMP 'par exemple pour alimenter une ListBox avec une liste triée sans doublon
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
        tmp = a(g): a(g) = a(d): a(d) = tmp
        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


0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
15 juil. 2015 à 18:09
https://www.cjoint.com/c/EGpqgUkZzvN

Je viens d'essayer dans le fichier que tu m'avais joint jeudi ...
Ben ça marche pas ... Le dictionnaire trié existe bien, mais uniquement dans le sub Tri.
Ce dictionnaire ne "remonte" pas dans le programme qui appel "Tri" :-/

(ou alors, c'est vraiment moi qui comprends rien ... je doute ... )
0
ThauTheme Messages postés 1442 Date d'inscription mardi 21 octobre 2014 Statut Membre Dernière intervention 29 juillet 2022 160
15 juil. 2015 à 18:15
Re, j'ai l'impression que tu ne regardes même pas les codes ! Lignes 8 à 11 du dernier code que je t'ai proposé C'est la variable TEMP qui est triée pas le dictionnaire !...
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
Modifié par wire less le 15/07/2015 à 18:32
Fuuuuuuuuuuhhhhh !!!
Je suis dyslexique du code !!!
Alors celui-là !! j'l'avais pas vu ! dsl de t'avoir fait perdre ton temps!
ça marche super bien à présent :-/
0

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

Posez votre question
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743
16 juil. 2015 à 11:32
Bonjour,

Je réagit juste à ceci :
ce qui est impossible pour les dico dans les user form
Ma question : pourquoi désires-tu utiliser des objets dictionary dans un UserForm?
La première réponse qui me vienne à l'esprit : le remplissage d'une liste (ComboBox ou ListBox).
Si oui, il ne m'apparait pas opportun d'utiliser des variables gourmandes comme les object dictionary pour se faire.
Tu dis...
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743
16 juil. 2015 à 12:17
Pour argumenter mon propos, voici le remplissage d'une combobox triée et sans doublon :
Private Sub UserForm_Initialize()
Dim TABLEAU As Variant, I As Long

TABLEAU = Sheets("Feuil1").Range("A2:A33")
Call Tri(TABLEAU, LBound(TABLEAU), UBound(TABLEAU))

For I = 1 To UBound(TABLEAU, 1)
    ComboBox1.Value = TABLEAU(I, 1)
     'on évite les doublons
    If ComboBox1.ListIndex = -1 Then ComboBox1.AddItem TABLEAU(I, 1)
Next I
End Sub

Sub Tri(a, gauc, droi) ' Quick sort
Dim ref, g, d, tmp
'Comme remplissage du tableau initial par l'objet Range
'il convient d'ajouter la dimension ( , 1) sous peine d'erreur 9
  ref = a((gauc + droi) \ 2, 1)
  g = gauc: d = droi
  Do
    Do While a(g, 1) < ref: g = g + 1: Loop
    Do While ref < a(d, 1): d = d - 1: Loop
    If g <= d Then
      tmp = a(g, 1): a(g, 1) = a(d, 1): a(d, 1) = tmp
      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
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
16 juil. 2015 à 16:41
Salut Pikaju!
Moi, j'avoue que utiliser des dictionnaires ... ou des ComboBox1.AddItem ...
J'avais juste besoin d'une méthode qui marche.

Par contre, ce qui m'a rendu dingue avec le script "ComboBox1.AddItem" c'est les déclenchement intempestif de combobox1_Click ... Fuuuuuhhhh ... Je me suis réellement rendu fou avec les Comobox.enabled = True/False ... jusqu'à qu'on me propose la méthode des dictionnaires.

Sinon, merci beaucoup pour ton aide.
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743 > wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018
16 juil. 2015 à 16:46
Hum hum...
Change() je veut bien, à la rigueur, mais Click()? Tu es sur de toi?

Pour tester : un userform, une combobox et le code suivant :
Private Sub ComboBox1_Change()
MsgBox "Change"
End Sub

Private Sub ComboBox1_Click()
MsgBox "Clic"
End Sub

Private Sub UserForm_Initialize()
Dim TABLEAU As Variant, I As Long

TABLEAU = Sheets("Feuil1").Range("A2:A6")
Call Tri(TABLEAU, LBound(TABLEAU), UBound(TABLEAU))

For I = 1 To UBound(TABLEAU, 1)
    ComboBox1.Value = TABLEAU(I, 1)
     'on évite les doublons
    If ComboBox1.ListIndex = -1 Then ComboBox1.AddItem TABLEAU(I, 1)
Next I
End Sub

Sub Tri(a, gauc, droi) ' Quick sort
Dim ref, g, d, tmp
'Comme remplissage du tableau initial par l'objet Range
'il convient d'ajouter la dimension ( , 1) sous peine d'erreur 9
  ref = a((gauc + droi) \ 2, 1)
  g = gauc: d = droi
  Do
    Do While a(g, 1) < ref: g = g + 1: Loop
    Do While ref < a(d, 1): d = d - 1: Loop
    If g <= d Then
      tmp = a(g, 1): a(g, 1) = a(d, 1): a(d, 1) = tmp
      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


Teste et dis moi...
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743
17 juil. 2015 à 10:01
Bonjour,

Pour en revenir à la question initiale, il est possible de faire une fonction perso dans le but d'ordonner un dictionary ET de récupérer, via cette fonction, un objet Dictionary.

Code de la fonction : [honteusement pompé sur le code de wire less...]
Function Ordonne_Dico(Dico As Object, Optional ByElem As Boolean) As Object
Dim ListeCle(), ListeElement(), I As Long, k As Long, Tempo_Cle, Tempo_Element

   ListeCle = Dico.Keys
   ListeElement = Dico.Items
   If ByElem Then
      For I = 0 To Dico.Count - 2
         For k = I + 1 To Dico.Count - 1
            If ListeElement(I) > ListeElement(k) Then
               Tempo_Cle = ListeCle(k)
               Tempo_Element = ListeElement(k)
               ListeElement(k) = ListeElement(I)
               ListeCle(k) = ListeCle(I)
               ListeCle(I) = Tempo_Cle
               ListeElement(I) = Tempo_Element
            End If
         Next k
      Next I
   Else
      For I = 0 To Dico.Count - 2
         For k = I + 1 To Dico.Count - 1
            If ListeCle(I) > ListeCle(k) Then
               Tempo_Cle = ListeCle(k)
               Tempo_Element = ListeElement(k)
               ListeElement(k) = ListeElement(I)
               ListeCle(k) = ListeCle(I)
               ListeCle(I) = Tempo_Cle
               ListeElement(I) = Tempo_Element
            End If
         Next k
      Next I
   End If
   Set Ordonne_Dico = CreateObject("Scripting.Dictionary")
   For I = LBound(ListeCle) To UBound(ListeCle)
      Ordonne_Dico.Add ListeCle(I), ListeElement(I)
   Next I
End Function


Cette fonction laisse à l'utilisateur le choix de trier par la clé ou par les éléments.
Pour l'appeler :
1- par la clé :
Sub test_ByCle()
Dim Mon_Dico As Object, TABLEAU, I As Long, Elem

   Set Mon_Dico = CreateObject("Scripting.Dictionary")
   TABLEAU = Sheets("Feuil1").Range("A1:A20")
   For I = 1 To UBound(TABLEAU, 1)
      Mon_Dico(TABLEAU(I, 1)) = ""
   Next I
   Set Mon_Dico = Ordonne_Dico(Mon_Dico) 'ByElem Optional = False
   '----------------------------------------Vérification :
   For Each Elem In Mon_Dico.Keys
      Debug.Print Mon_Dico(Elem) & " - " & Elem
   Next
End Sub

2- par les éléments:
Sub test_ByElem()
Dim Mon_Dico As Object, TABLEAU, I As Long, Elem

   Set Mon_Dico = CreateObject("Scripting.Dictionary")
   TABLEAU = Sheets("Feuil1").Range("A1:A20")
   For I = 1 To UBound(TABLEAU, 1)
      Mon_Dico(TABLEAU(I, 1)) = I
   Next I
   Set Mon_Dico = Ordonne_Dico(Mon_Dico, True) 'ByElem = True
   '----------------------------------------Vérification :
   For Each Elem In Mon_Dico.Keys
      Debug.Print Mon_Dico(Elem) & " - " & Elem
   Next
End Sub


C'est juste pour le fun, bien entendu!
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
Modifié par wire less le 17/07/2015 à 14:39
Bien entendu ...
Non non non ... pas "bien entendu" ... C'est juste de la bombe ce que tu viens de faire !!
C'est pas du "Fun" C'est de l'art ! :-D
La voila la fonction magique qui ordonne un dictionnaire. Tu viens de la créer!
Si tu as le n° de téléphone de Jacques Boisgontier je l'appel tout de suite pour qu'il rajoute cette fonction à son site!

C'était le chaînon manquant ... c'est comme si tu venais de démontrer l'existence de la masse noir de l'univers.
Voila ! On peut enfin créer une combo-box proprement ... sans doublons et ordonné à partir d'un dictionnaire !! C'est pas rien.
C'est fantastique !!

Et je mesure juste toute les lacune que j'ai !!

pourquoi :
   
For I = LBound(ListeCle) To UBound(ListeCle)
Ordonne_Dico.Add ListeCle(I), ListeElement(I)
Next I

Et non pas :
For I = LBound(ListeCle) To UBound(ListeCle)
    Ordonne_Dico(ListeCle(I)) = ListeElement(I)
Next I


Et tant d'autres questions ...
Merci encore.
(Ps, je n'ai pas eu le temps de tester le script que tu m'as proposé plus haut ... mais je ne doute pas qu'il doit marcher ... j'essayerais plus tard ... j'ai encore trop de trucs à "débugger" dans mon code ...
(si tu as un peu de temps à perdre, tu peux peut-être répondre aux quelques questions que j'ai posé là :
https://forums.commentcamarche.net/forum/affich-32212197-combobox-et-listindex#p32224355
même si c'est juste des questions de curiosités )
Sinon :

For i = 1 to 1000
Call Msgbox(" MERCI ")
Next i


Bon, j'exagère peut-être un peu !! Mais en tout cas, merci !
A+
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743 > wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018
17 juil. 2015 à 15:11
Bonjour,

pourquoi :
For I = LBound(ListeCle) To UBound(ListeCle)
Ordonne_Dico.Add ListeCle(I), ListeElement(I)
Next I


Et non pas :
For I = LBound(ListeCle) To UBound(ListeCle)
    Ordonne_Dico(ListeCle(I)) = ListeElement(I)
Next I


===> Aucune différence. C'est toi qui choizz

Voila ! On peut enfin créer une combo-box proprement ... sans doublons et ordonné à partir d'un dictionnaire !! C'est pas rien.

Ben, en fait, on pouvait déjà! Et sans dictionary! Cf mes codes d'hier.
Ce qui est encore mieux...
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5
17 juil. 2015 à 15:36
Pia pia pia ... oui ... mais moi j'avais pas réussi ... promis je regarderais le pourquoi de mes "combobox1_Click" intempestif ... c'est peut-être juste que j'avais codé avec mes pieds ce qui est aussi très possible, je ne suis pas encore un master du combobox comme toi :-p.
sinon, chez moi
For I = LBound(ListeCle) To UBound(ListeCle)
    Ordonne_Dico(ListeCle(I)) = ListeElement(I)
Next I

Ben ça ne marche pas ... Ben ... ça ne veux pas dire qu'en général ça ne marche pas ... c'était peut-être un autre beugge à côté ... m'enfin ... je suis content d'avoir un code qui marche ... et qui est super rapide en plus.
Thx !
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 2 743 > wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018
17 juil. 2015 à 15:42
Ou c'est peut-être que comme un idiot, j'ai mélangé les Items et les Keys...
Essaye juste en changeant :
 Ordonne_Dico(ListeElement(I)) = ListeCle(I)

et si cela fonctionne c'est que j'ai fait l'échange quelque part...
0
wire less Messages postés 210 Date d'inscription lundi 5 octobre 2009 Statut Membre Dernière intervention 29 août 2018 5 > pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024
17 juil. 2015 à 18:27
:-/ non non ... c'était bien Ordonne_Dico(ListeCle(I)) = ListeElement(I)
0