IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Philippe Tulliez

[Actualité] VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject)

Noter ce billet
par , 17/03/2023 à 07h29 (37002 Affichages)
Préambule
Il arrive régulièrement que nous devions utiliser une liste de valeurs uniques au sein d'une plage de données.
Il y a évidemment de nombreuses méthodes pour y arriver. J'en ai choisi deux. La première utilise la fonction Evaluate en y incluant comme argument, la fonction native d'excel UNIQUE (uniquement pour la version 365) et la seconde utilise l'objet Dictionary.
Chacune d'elles est présentée au sein d'une fonction générique.

Nom : 230315 - Data.png
Affichages : 4706
Taille : 53,9 Ko

Exemple choisi
Pour l'exemple, nous allons choisir d'obtenir les éléments uniques de la colonne Statut du tableau structuré nommé t_Data comme illustré plus haut.

La fonction générique
La fonction générique nommée GetUniqueValue renvoie une table à une dimension contenant les éléments uniques de la colonne d'un tableau structuré dont les noms sont passés en arguments (TableName et LabelName)

Important : La table dont le nom est passé en argument est sensé être présente dans le classeur actif et le nom de la colonne doit exister (la fonction présentée ici ne le contrôle pas) .

Code de la procédure (Exemple 1)
Utilisation de la fonction native d'excel UNIQUE comme argument de la fonction VBA Evaluate.
Pour l'exemple choisi, la formule est =UNIQUE(t_Data[Statut])
Attention, pour utiliser cette première procédure, il faut la version 365

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Function GetUniqueValue(TableName As String, LabelName As String)
  ' Renvoie la liste des éléments unique présents dans la colonne du tableau passé par arguments
  ' Philippe Tulliez (https://magicoffice.be)
  ' Arguments
  '   TableName  Nom du tableau
  '   LabelName  Etiquette de la colonne
  ' Déclaration
  Const FormulaPattern As String = "=UNIQUE(<Table>[<Label>])" ' Modèle de la formule
  Dim f As String
  ' Remplacement des balises <Table> et <Label> par les arguments passés
  f = Replace(FormulaPattern, "<Table>", TableName)
  f = Replace(f, "<Label>", LabelName)
  ' Renvoi des éléments uniques
  GetUniqueValue = Application.Transpose(Evaluate(f))
End Function

Code de la procédure (Exemple 2)
Utilisation de l'objet Dictionary en Late Binding
Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Function GetUniqueValue(TableName As String, LabelName As String)
  ' Renvoie un Array contenant la valeur Unique dans une colonne
  '   Utilise l'objet Dictionary en Late Binding
  ' Philippe Tulliez (https://magicoffice.be)
  ' Arguments
  '   TableName  Nom du tableau
  '   LabelName  Etiquette de la colonne
  '
  ' Déclaration et affectation
  Dim l As ListObject, c As Range, d As Object
  Dim t As Variant, e As Long
  Set l = Range(TableName).ListObject
  Set d = CreateObject("Scripting.Dictionary") ' Late Binding
  t = l.ListColumns(LabelName).DataBodyRange.Value
  ' Chargement des données
  With d
    For e = 1 To UBound(t): .Item(t(e, 1)) = t(e, 1): Next
    GetUniqueValue = .items
  End With
  ' Libère la mémoire
  Set l = Nothing: Set c = Nothing: Set d = Nothing
End Function

Exemples pour l'invoquer

Exemple 1
Affiche à l'aide d'un MsgBox, la liste des valeurs uniques de la colonne Statut du tableau structuré t_data
Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
Sub TestGetUniqueValue_1()
  Dim t As Variant
  t = GetUniqueValue("t_data", "Statut")
  If IsArray(t) Then MsgBox Join(t, vbCrLf)
End Sub

Exemple 2
Alimente le ListBox (ListBox1) d'un UserForm nommé usf_List de la liste des valeurs uniques de la colonne Statut du tableau structuré t_data
Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
Sub TestGetUniqueValue_2()
  ' Charge les valeurs uniques de la colonne Statut du tableau t_Data
  '   dans un ListBox d'un UserForm
  With usf_List
  .ListBox1.List = GetUniqueValue("t_data", "Statut")
  .Show
  End With
End Sub

Exemple 3
Crée dynamiquement les onglets d'un TabStrip (TabStrip1) d'un UserForm (UserForm1) avec les valeurs uniques de la colonne Statut du tableau t_Data

Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Sub TestGetUniqueValue_3()
  Dim t As Variant
  Dim e As Integer
  t = GetUniqueValue("t_data", "Statut")
  With UserForm1
    With .TabStrip1
    .Tabs.Clear
     For e = LBound(t) To UBound(t)
      .Tabs.Add 1, t(e)
     Next
    End With
  .Show
  End With
End Sub

Nom : Capture d'écran 2023-03-17 075533.png
Affichages : 2764
Taille : 19,7 Ko

Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Viadeo Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Twitter Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Google Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Facebook Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Digg Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Delicious Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog MySpace Envoyer le billet « VBA - EXCEL Comment renvoyer dynamiquement les valeurs uniques de la colonne d'un tableau (ListObject) » dans le blog Yahoo

Mis à jour 27/03/2023 à 08h47 par Philippe Tulliez

Catégories
VBA Excel

Commentaires

  1. Avatar de laurent_ott
    • |
    • permalink
    N'ayant pas la version 365 d'Excel je n'ai pas pu tester la méthode avec l'utilisation de la fonction native UNIQUE.
    Cependant il faudrait tester sur une grande liste de valeurs uniques (de plus de 65 535 données) car la méthode Application.Transpose dans les versions antérieures à Excel 365 renvoyait dans ce cas des données erronées, afin de s'assurer que les ingénieurs de Microsoft ont résolu ce problème.

    Concernant la méthode qui utilise l'objet Dictionary, il faut noter que cet objet ne trie pas les valeur uniques (en tout cas dans ma version d'Excel).
    Pour obtenir une liste triée par ordre croissant il convient : soit de trier les données préalablement dans le tableau structuré, soit de les trier par programmation après leur chargement.

    Pour cette dernière approche il faut utiliser un algorithme de tri rapide comme QuickSort.
    Mais du coup il devient inutile d'utiliser l'objet Dictionary puisque pour avoir la liste des valeurs uniques il suffit simplement de ne retenir dans la liste triée que les valeurs différentes des valeurs suivantes, ce que le VBA sait faire.
    En plus le traitement est plus rapide qu'avec Dictionary, bien que pour l'utilisateur cela n'est perceptible que sur de grandes listes de données (sur une liste de 500 000 lignes contenant des valeurs aléatoires comprises entre 1 et 300 000 on passe de 3 secondes à 0,5 seconde de traitement).

    Ce qui donnerait la fonction suivante en reprenant les conditions précitées :

    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    '----------------------------------------------------------------------------------------
    Function GetUniqueValueSort(TableName As String, LabelName As String)
    '----------------------------------------------------------------------------------------
    ' Renvoie un Array contenant la valeur Unique dans une colonne
    ' Arguments
    '   TableName  Nom du tableau
    '   LabelName  Etiquette de la colonne
    '----------------------------------------------------------------------------------------
    ' Déclarations
    Dim X() As Variant, T As Variant
    Dim i As Long, k As Long
    ' Chargement des données
    X = Range(TableName).ListObject.ListColumns(LabelName).DataBodyRange.Value
    ' Tri des données:
    Call TS_QuickSort(X(), 1, UBound(X))
    ' Récupération des données uniques
    ReDim T(0 To UBound(X) - 1)
    T(0) = X(1, 1)
    For i = 1 To UBound(X)
        If X(i, 1) <> T(k) Then k = k + 1: T(k) = X(i, 1)
    Next i
    ' Renvoie les valeurs uniques
    ReDim Preserve T(0 To k)
    GetUniqueValueSort = T
    End Function
     
    '----------------------------------------------------------------------------------------
    Private Sub TS_QuickSort(ByRef TabDonnées() As Variant, ByVal Gauche As Long, ByVal Droite As Long)
    '----------------------------------------------------------------------------------------
    ' Algorithme QuickSort optimisé pour trier une colonne d'un tableau structuré.
    '----------------------------------------------------------------------------------------
    Dim i As Long, j As Long, Temp As Variant, Pivot As Variant
     
    i = Gauche
    j = Droite
    Pivot = TabDonnées((Gauche + Droite) / 2, 1)
     
    Do
        While Pivot > TabDonnées(i, 1): i = i + 1: Wend
        While TabDonnées(j, 1) > Pivot: j = j - 1: Wend
     
        If j + 1 > i Then
            Temp = TabDonnées(i, 1)
            TabDonnées(i, 1) = TabDonnées(j, 1)
            TabDonnées(j, 1) = Temp
            j = j - 1: i = i + 1
        End If
     
    Loop Until i > j
     
    If Gauche < j Then Call TS_QuickSort(TabDonnées(), Gauche, j)
    If i < Droite Then Call TS_QuickSort(TabDonnées(), i, Droite)
     
    End Sub
    '----------------------------------------------------------------------------------------

    Et l'appel :

    Code VBA : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Sub Test_GetUniqueValueSort()
    Dim V As Variant, i As Long
    V = GetUniqueValueSort("t_data", "Statut")
    For i = 0 To UBound(V)
        Debug.Print V(i)
    Next i
    End Sub
    Cordialement.
  2. Avatar de Philippe Tulliez
    • |
    • permalink
    Bonjour Laurent,
    Désolé de répondre tardivement à ce message que je découvre à l'instant.
    Effectivement, j'ai omis de préciser la limite de la fonction Transpose qui est toujours présente dans la version 365.
    J'avoue que je n'ai jamais pensé un instant d'utiliser une liste unique contenant autant d'éléments mais tu as raison, je dois prévoir un renvoi d'erreur si cette liste contient plus de 65536 lignes uniques. C'est inscrit dans mon agenda

    En ce qui concerne le tri , ce n'était pas le but du billet dont le sujet était de renvoyer une liste unique. Libre au programmeur de le faire après l'extraction des valeurs uniques.

    Citation Envoyé par laurent_ott
    N'ayant pas la version 365 d'Excel je n'ai pas pu tester la méthode avec l'utilisation de la fonction native UNIQUE.
    Cependant il faudrait tester sur une grande liste de valeurs uniques (de plus de 65 535 données) car la méthode Application.Transpose dans les versions antérieures à Excel 365 renvoyait dans ce cas des données erronées, afin de s'assurer que les ingénieurs de Microsoft ont résolu ce problème.

    Concernant la méthode qui utilise l'objet Dictionary, il faut noter que cet objet ne trie pas les valeur uniques (en tout cas dans ma version d'Excel).
    Pour obtenir une liste triée par ordre croissant il convient : soit de trier les données préalablement dans le tableau structuré, soit de les trier par programmation après leur chargement.