Problème pour coder une macro

Bonjour à tous,

je sollicite votre aide pour m'aider à trouver une solution à un problème que je rencontre sur le fichier ci-joint.

Ca c'est un screen de la feuille 2 :

image

Et j'aimerais que mon code donne comme sur le screen de la feuille 1 :

image

C'est à dire pour vous expliquer :

Dans la feuille 2, si la valeur de la ligne en colonne A et en colonne D est identique à une autre valeur de la ligne en colonne A et en colonne D (comme ligne 1,2,3 dans l'exemple) alors dans la feuille 1 le code indique juste une ligne (pour rassembler les 3) avec en colonne E les valeurs de la colonne E de la feuille 2.

Si il y a qu'une seule fois la combinaison de la valeur de la colonne A et D (sur la feuille 2) alors une ligne est créée en feuille 1 (cf. lignes 2 et 3 de la feuille 1).

J'espère avoir été suffisamment précis dans mes explications pour que vous compreniez la problématique (pour info, le fichier est beaucoup plus volumineux que ça en vrai).

J'ai tenté avec qqch du type :

Sub X

Dim M as Integer 

M = 2000

         For i = 1 to M
                 if feuille2.cells(I, 1).Value = feuille2.cells(I + 1, 1).Value then 
                    feuille1.cells(I, 1) = feuille2.cells(I, 1).Value
                endif
       Next i

endsub

C'était déjà pour récupérer A1 de la feuille 2 pour l'envoyer dans la feuille 1.

Mais bon c'est très sommaire et ça ne fonctionne pas (j'ai l'impression que ça fait déjà lagger le PC avec qqs lignes).

Est-ce que qq'un pourrait m'aider s'il vous plaît, je suis dans le flou en fait, et je n'arrive pas à voir comment faire en fait.

Je vous remercie par avance.

5classeur-6.ods (10.25 Ko)

Bonjour tout le monde.

Est-ce que qq'un aurait une piste à me partager s'il vous plaÎt, je reste bloqué en fait..

Bonjour,

Essaye cette macro et dis-moi si cela t'aide:

Sub X()

Dim ligneA As Integer
Dim ligneB As Integer
Dim ligneC As Integer
Dim test As Integer

Dim donnéeA As String
Dim donnéeB As String
Dim donnéeC As String
Dim donnéeD As String

M = 1000 'nombre de lignes à tester
Sheets("Feuil2").Copy after:=Sheets(1) ' copie de sécurité de la page
ligneC = 1

Sheets("Feuil2").Activate
For ligneA = 1 To M 'je défini une première ligne
test = 0

donnéeA = Sheets("Feuil2").Cells(ligneA, 1)
donnéeC = Sheets("Feuil2").Cells(ligneA, 4)

For ligneB = ligneA + 1 To M 'je défini une 2ème ligne
donnéeB = Sheets("Feuil2").Cells(ligneB, 1)
donnéeD = Sheets("Feuil2").Cells(ligneB, 4)
    'je vais comparer ma première ligne à toutes les deuxièmes lignes
    If Not IsEmpty(Cells(ligneB, 1)) And donnéeA = donnéeB And donnéeC = donnéeD Then
    ' si c'est bon je copie mes deux premières cases sur la feuille 1
    Sheets("Feuil1").Cells(ligneC, 1) = Sheets("Feuil2").Cells(ligneA, 1).Value
    Sheets("Feuil1").Cells(ligneC, 4) = Sheets("Feuil2").Cells(ligneA, 4).Value
            'pour la troisième case, si la case est vide je copie valeur a et dessous valeur b
            If Sheets("Feuil1").Cells(ligneC, 5) = "" Then
            Sheets("Feuil1").Cells(ligneC, 5) = Sheets("Feuil2").Cells(ligneA, 5).Value & Chr(10) & Sheets("Feuil2").Cells(ligneB, 5).Value
            ' sinon je garde sa propre valeur et en dessous je copie valeur a et en dessous valeur b
            Else
            Sheets("Feuil1").Cells(ligneC, 5) = Sheets("Feuil1").Cells(ligneC, 5).Value & Chr(10) & Sheets("Feuil2").Cells(ligneB, 5).Value
            End If
    ' je met ma valeur test à 1 pour dire que j'ai déjà copié mes valeurs ligneA
    test = 1
    ' et j'efface ma ligneB pour ne pas la retraiter
    Rows(ligneB) = ""
    End If

Next ligneB

                ' quand j'ai traité toutes mes lignesB pour ma ligneA
                ' si j'ai pas copié ma ligneA je la copie 
                If test = 0 Then
                Sheets("Feuil1").Cells(ligneC, 1) = Sheets("Feuil2").Cells(ligneA, 1).Value
                Sheets("Feuil1").Cells(ligneC, 4) = Sheets("Feuil2").Cells(ligneA, 4).Value
                Sheets("Feuil1").Cells(ligneC, 5) = Sheets("Feuil2").Cells(ligneA, 5).Value
                End If
                ' et dans tous les cas, j'en ai fini donc je l'efface
                Rows(ligneA) = ""

    ' si ma ligneC (ligne qui défini ou je colle mes valeurs en fuille1) est remplie, je passe à la suivante
    If Not IsEmpty(Sheets("Feuil1").Cells(ligneC, 1)) Then
    ligneC = ligneC + 1
    End If

Next ligneA

Application.DisplayAlerts = wdAlertsNone 'j'enlève l'alerte car je vais supprimer un onglet

Sheets("Feuil2").Delete ' j'efface ma feuille 2
Sheets("Feuil2 (2)").Name = "Feuil2" ' que je remplace par sa copie de sécurité 
End Sub
3classeur-6.xlsm (17.25 Ko)

Merci beaucoup ZeChris pour ta réponse.

Je viens de tester la macro, mais cela fait tourner en boucle Excel.

J'essaie de voir pourquoi.

Bonjour,

Cette macro te fera ça aux petits oignons.... Pour peu que tu mettes quelque chose en B1 et C1 !

Sub Galopin()
Dim Arr, T, i%, Dec%, S$, Dico
   Set Dico = CreateObject("scripting.dictionary")
   Arr = Feuil2.[A1].CurrentRegion.Value
   i = 1
   Dec = 1
    S = Arr(i, 4) & Chr(124) & Arr(i, 5)
   Do Until i = UBound(Arr)
    If Arr(i + Dec, 1) = Arr(i, 1) Then
        S = S & Chr(10) & Arr(i + Dec, 5)
        Dec = Dec + 1
    Else
    Dico(Arr(i, 1)) = S
        i = i + Dec
        Dec = 1
    S = Arr(i, 4) & Chr(124) & Arr(i, 5)
    End If
   Loop
    Dico(Arr(i, 1)) = S
Feuil1.[A1].Resize(Dico.Count, 1) = Application.Transpose(Dico.keys)
T = Application.Transpose(Dico.items)
For i = 1 To Dico.Count
Feuil1.Cells(i, 4) = Split(T(i, 1), "|")(0)
Feuil1.Cells(i, 5) = Split(T(i, 1), "|")(1)
Next
End Sub

A+

Merci galopin01, c'est trop cool ça fonctionne :)

Je vais adapter ta structure à mon gros fichier et normalement le pb sera résolu :)

Bonjour Galopin.

Pourrais-tu m'expliquer en deux mots le principe de ta macro s'il te plait ?

Je la comprends pas trop (je suis autodidacte et pas encore très au point, y qu'à voir comme mon code fait ramer le PC de Lafrog )

Merci d'avance

Bonjour,

Ce problème n'a que l'apparence de la simplicité ! Pour coder ça en évitant de faire ramer le PC il n'y a qu'une solution : Ne surtout pas travailler sur les feuilles, mais travailler sur des Array (tableaux) en mémoire. Le travail sur les Array divise le temps de W par 20 : Le travail est exactement le même que sur feuille sauf que les Array n'ont aucune formule, aucun format, donc le processeur n'a pas à s'occuper de toutes les liens entre les propriétés internes liées aux feuilles et aux cellules. Il ne gère que des tableaux avec des lignes et des colonnes et des valeurs dedans. Une fois le tableau rempli

Arr = Feuil2.[A1].CurrentRegion.Value 

YAPUKA parcourir cet Array (Arr) :

Arr(1,1) = Cellule"A1"
Arr(1,2) = Cellule"B1"
Arr(2,1) = Cellule"A2"

Dès lors l'algorithme est le même que si on travaillait sur une feuille :

'On parcoure le tableau (Array)
'Pour charger le Dictionnary au fur et à mesure
i = 1
Dec = 1
S = Arr(i, 4) & Chr(124) & Arr(i, 5)
Do Until i = UBound(Arr)
    If Arr(i + Dec, 1) = Arr(i, 1) Then
        S = S & Chr(10) & Arr(i + Dec, 5)
        Dec = Dec + 1
    Else
        Dico(Arr(i, 1)) = S
        i = i + Dec
        Dec = 1
        S = Arr(i, 4) & Chr(124) & Arr(i, 5)
    End If
   Loop
Dico(Arr(i, 1)) = S

On parcoure et on compare toutes la colonne 1 et si la cellule suivante est identique on génére un Dictionnary dont le principe est encore plus rapide que les Array : Là le gain de temps est encore plus important (on divise encore par 5) car le Dictionnary ne s'occupe pas de tableaux mais il se comporte comme un dictionnaire. C'est la force de cette programmation : on gère un super Larousse de chaînes de caractères séparées par des caractères (ici des pipes Chr(124) = "|" ) La restitution est très simple elle se fait un peu de la même manière que la fonction "Convertir" du ruban "Données"…

'YAPUKA décharger le Dico ou on veut !
Feuil1.[A1].Resize(Dico.Count, 1) = Application.Transpose(Dico.keys)
T = Application.Transpose(Dico.items)
For i = 1 To Dico.Count
    Cells(i, 4) = Split(T(i, 1), "|")(0)
    Cells(i, 5) = Split(T(i, 1), "|")(1)
Next

Bon c'est un peu complexe, traduire ça au ligne par ligne n'a à mon avis aucun sens car on distingue deux traitements différents la colonne 1 qui récupère les "keys" du Dico : La récupération est très simple 1 seule ligne… Et les données parsées des colonnes 4 et 5 qui passent par un Array intermédiaire (T)

Euh… Toussa c'est 30 ans de pratique résumées en quelques lignes. Ça se digère à dose homéopathique !

A+

Merci beaucoup pour toutes ces informations.

Je vais me prendre un petit doliprane et m’atteler à tout ça. Je vois que j'ai encore une belle marge de progression !

Merci en tous cas d'avoir pris le temps de me répondre. Je vais reprendre ça à tête reposée et essayer de saisir le concept, ce sera déjà je pense un grand pas en avant.

Chaque chose en son temps !!!!! Apprendre à marcher avant de courir.

Au plaisir de te recroiser sur le forum.

Rechercher des sujets similaires à "probleme coder macro"