Ca ne rentre pas à chaque fois dans ma tête ! (dictionnary)

Hello tous,

J'ai déjà réussi à faire des macros avec Dictionnary mais là , c'est tout simple en apparence, mais je bloque...

Un tableau sur la partie gauche de l'écran ,en 4 colonnes, mais il pourrait y en avoir plus; un nombre de lignes avec des noms en multiples exemplaires et qui peuvent être bien sur plusieurs milliers; l'exemple en montre peu mais c'est pour connaitre la marche à suivre qu'il est fait.

Je dois faire un résumé autrement qu'avec TCD ou sommeprod et autres formules diverses; je tiens à faire ça en vba parce que la vitesse est un critère si j'ai 10.000 lignes et 40 colonnes

Merci de votre aide précieuse !

Patrick

Bonjour,

Une piste à améliorée mais ça te donne le résultat voulu :

Sub RegrouperParNoms()

    Dim Dico As Object
    Dim Plage As Range
    Dim Cel As Range
    Dim NumCol As Long
    Dim I As Long
    Dim Chaine As String
    Dim Cle

    With Worksheets("Feuil1")

        'défini la plage sur la colonne A
        Set Plage = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))

        'récup du nombre de colonnes sur la linge 1
        NumCol = .Cells(1, .Columns.Count).End(xlToLeft).Column

    End With

    'vide les cellules en décalé d'une colonne à droite de la plage, dans l'exemple F1:J17
    Plage.Offset(, NumCol + 1).Resize(Plage.Rows.Count, Plage.Columns.Count + NumCol).Clear

    Set Dico = CreateObject("Scripting.Dictionary")

    'parcour la plage (colonne A)
    For Each Cel In Plage

        'si la clé n'existe pas...
        If Dico.exists(Cel.Value) = False Then

            'construction de la chaine
            For I = 1 To NumCol

                Chaine = Chaine & Cel.Offset(, I).Value & ";"

            Next I

            'création de la clé et ajout de la chaine
            Dico.Add Cel.Value, Chaine

            'efface
            Chaine = ""

        'si la clé existe déjà...
        Else

            'ajoute les valeurs manquantes
            For I = 1 To NumCol

                If Split(Dico(Cel.Value), ";")(I - 1) = "" Then
                    Chaine = Chaine & Cel.Offset(, I).Value & ";"
                Else
                    Chaine = Chaine & Split(Dico(Cel.Value), ";")(I - 1) & ";"
                End If

            Next I

            'puis remplacement de la valeur par la nouvelle
            Dico(Cel.Value) = Chaine

            'efface
            Chaine = ""

        End If

    Next Cel

    I = 0

    'colle dans la zone précédemment vidée. Pour plus de rapidité, à voir ici pour l'utilisation d'un tableau intermédiaire !!!
    For Each Cle In Dico.Keys

        I = I + 1
        Range("F" & I) = Cle
        Range("G" & I & ":I" & I) = Split(Dico(Cle), ";")

    Next Cle

End Sub

Avec un tableau et avec une petite correction au niveau de la recherche de la dernière colonne (pour le vidage des cellules) :

Sub RegrouperParNoms()

    Dim Dico As Object
    Dim Plage As Range
    Dim Cel As Range
    Dim Tbl() As String
    Dim NumCol As Long
    Dim I As Long
    Dim J As Integer
    Dim Chaine As String
    Dim Cle

    With Worksheets("Feuil1")

        'défini la plage sur la colonne A
        Set Plage = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp))

        'récup du nombre de colonnes sur la linge 1
        NumCol = .Cells(1, 1).End(xlToRight).Column

    End With

    'vide les cellules en décalé d'une colonne à droite de la plage, dans l'exemple F1:J17
    Plage.Offset(, NumCol + 1).Resize(Plage.Rows.Count, Plage.Columns.Count + NumCol).Clear

    Set Dico = CreateObject("Scripting.Dictionary")

    'parcour la plage (colonne A)
    For Each Cel In Plage

        'si la clé n'existe pas...
        If Dico.exists(Cel.Value) = False Then

            'construction de la chaine
            For I = 1 To NumCol

                Chaine = Chaine & Cel.Offset(, I).Value & ";"

            Next I

            'création de la clé et ajout de la chaine
            Dico.Add Cel.Value, Chaine

            'efface
            Chaine = ""

        'si la clé existe déjà...
        Else

            'ajoute les valeurs manquantes
            For I = 1 To NumCol

                If Split(Dico(Cel.Value), ";")(I - 1) = "" Then
                    Chaine = Chaine & Cel.Offset(, I).Value & ";"
                Else
                    Chaine = Chaine & Split(Dico(Cel.Value), ";")(I - 1) & ";"
                End If

            Next I

            'puis remplacement de la valeur par la nouvelle
            Dico(Cel.Value) = Chaine

            'efface
            Chaine = ""

        End If

    Next Cel

    I = 0

    ReDim Tbl(1 To Dico.Count, 1 To NumCol)

    'colle dans la zone précédemment vidée
    For Each Cle In Dico.Keys

        I = I + 1
        Tbl(I, 1) = Cle

        For J = 2 To UBound(Split(Dico(Cle), ";"))
            Tbl(I, J) = Split(Dico(Cle), ";")(J - 2)
        Next J

    Next Cle

   Range(Cells(1, NumCol + 2), Cells(Dico.Count, NumCol * 2 + 1)) = Tbl

End Sub

Bonjour,

Si j'ai compris ce que tu veux obtenir (pas sûr ! certains éléments de ton cheminement m'ont un peu troublé), j'aurais procédé ainsi avec éléments que tu as mis en avant (c'est un peu différent de Thèze, que j'ai regardé rapidement au passage) :

Sub RegrouperParNoms()
    Dim Dico As Object
    Dim C
    Dim Tablo
    Dim A, I
    Set Dico = CreateObject("Scripting.Dictionary")
    For Each C In Range("a1", [a65000].End(xlUp))
        A = Array(C.Value, C.Offset(0, 1), C.Offset(0, 2), C.Offset(0, 3))
        If Dico.exists(C.Value) Then
            Tablo = Split(Dico(C.Value), "|")
            For I = 0 To UBound(A)
                If IsEmpty(A(I)) Then A(I) = Tablo(I)
            Next I
        End If
        Dico(C.Value) = Join(A, "|")
    Next C
    [G2].CurrentRegion.ClearContents
    Tablo = Dico.items
    C = 0
    For I = LBound(Tablo) To UBound(Tablo)
        A = Split(Tablo(I), "|")
        C = C + 1
        Range("G" & C).Resize(, UBound(Tablo)) = A
    Next I
End Sub

Cordialement.

Re bonjour à vous 2, et aux autres

je teste ça lundi et je vous tiens au jus

Merci déjà !

P.

Bonsoir le forum,

Salut patrick,

Pas trop compris le contexte

On voit toujours apparaitre la même occurence dans chacune de tes colonnes (2 à 4), est-ce normal ?

Option Explicit

Sub test()
Dim a, i As Long, j As Long, n As Long, w()
    With Sheets(1).Range("a1").CurrentRegion
        a = .Value
        ReDim w(1 To UBound(a, 2)): n = 1
        With CreateObject("Scripting.Dictionary")
            .CompareMode = 1
            For i = 2 To UBound(a, 1)
                If Not .exists(a(i, 1)) Then
                    n = n + 1
                    w(1) = n
                    a(n, 1) = a(i, 1)
                    For j = 2 To UBound(a, 2)
                        Set w(j) = CreateObject("Scripting.Dictionary")
                        w(j).CompareMode = 1
                        If a(i, j) <> "" Then
                            w(j)(a(i, j)) = Empty
                        End If
                        a(n, j) = a(i, j)
                    Next
                    .Item(a(i, 1)) = w
                Else
                    w = .Item(a(i, 1))
                    For j = 2 To UBound(a, 2)
                        If a(i, j) <> "" Then
                            If Not w(j).exists(a(i, j)) Then
                                a(w(1), j) = a(i, j)
                                w(j)(a(i, j)) = Empty
                                .Item(a(i, 1)) = w
                            End If
                        End If
                    Next
                End If
            Next
        End With
        Application.ScreenUpdating = False
        'Restitution
        With .Offset(, .Columns.Count + 2)
            .Cells(1).CurrentRegion.Clear
            With .Resize(n, UBound(a, 2))
                .Value = a
                .BorderAround Weight:=xlThin
                .Borders(xlInsideVertical).Weight = xlThin
                .Borders(xlInsideHorizontal).Weight = xlThin
                .VerticalAlignment = xlCenter
                With .Rows(1)
                    .Interior.ColorIndex = 36
                End With
            End With
        End With
        Application.ScreenUpdating = True
    End With
End Sub

klin89

Re patrick,

Vu le contexte, plus simple :

Option Explicit

Sub test1()
Dim a, i As Long, j As Byte, w(), y, x
    With Sheets(1).Range("a1").CurrentRegion
        a = .Value
        With CreateObject("Scripting.Dictionary")
            .CompareMode = 1
            For i = 2 To UBound(a, 1)
                If Not .exists(a(i, 1)) Then
                    ReDim w(1 To UBound(a, 2))
                    For j = 1 To UBound(a, 2)
                        w(j) = a(i, j)
                    Next
                    .Item(a(i, 1)) = w
                Else
                    w = .Item(a(i, 1))
                    For j = 2 To UBound(a, 2)
                        If a(i, j) <> "" Then
                            If w(j) = "" Then
                                w(j) = a(i, j)
                            End If
                        End If
                    Next
                    .Item(a(i, 1)) = w
                End If
            Next
            y = .Count: x = .items
        End With
        Application.ScreenUpdating = False
        'Restitution
        With .Offset(, .Columns.Count + 2)
            With .Cells(1)
                .CurrentRegion.Clear
                .Resize(1, UBound(a, 2)).Value = a
                .Offset(1).Resize(y, UBound(a, 2)).Value = Application.Index(x, 0, 0)
                With .CurrentRegion
                    .BorderAround Weight:=xlThin
                    .Borders(xlInsideVertical).Weight = xlThin
                    .Borders(xlInsideHorizontal).Weight = xlThin
                    .VerticalAlignment = xlCenter
                    With .Rows(1)
                        .Interior.ColorIndex = 36
                    End With
                End With
            End With
        End With
        Application.ScreenUpdating = True
    End With
End Sub

klin89

Hello à tous,

Alors, avec un test sur vos différents codes, c'est génial comme toujours

J'ai essayé avec le tableau déposé au premier post:

Theze: tel quel , le tableau se reproduit tel que le résultat escompté

si j'ajoute une personne sur plusieurs lignes , pas de souci

si j'insère une colonne en 2e position par ex, c'est OK aussi

(merci pour les commentaires dans le code)

MFerrand (code plus court et plus simple à comprendre -pour mon esprit mononeurone- )

tableau originel: OK

avec une personne en plus et sur plusieurs lignes:Ok

en insérant une colonne en plus en 2e position: Ok

klin89 Idem, tout fonctionne mais j'ai aussi vu de nombreuses bonnes réponses de sa part sur différents sujets

Donc, bravo à vous tous, je garde ça précieusement et j'utiliserai certainement encore dans le futur en adaptant à mes autres classeurs ou pour tenter des réponses -- adaptées -- à d'autres participants.

Merci à vous tous !

Ceci dit, je poserai surement encore un ou l'autre question à l'avenir parce que j'ai du mal à appréhender les dico et leur clé , même si j'en comprends le principe et que j'ai parcouru le site de Boisgontier et...que je sais parfois répondre sur des codes plus simples; ici le mélange tableau/dico (code de Klin89) me perturbe mais tout en sachant que sur un grand nombre de données il est rapide.

Patrick (qui aurait besoin de cours en "dicologie" )

Rechercher des sujets similaires à "rentre pas chaque fois tete dictionnary"