Option Explicit
Sub Macro1()
Dim DEB As Double ' déclare la variable DEB (DÉBut)
Dim OB As Worksheet 'déclare la variable OB (Onglet Base)
Dim D As Object 'déclare la variable D (Dictionnaire)
Dim DL As Integer 'déclare la variable DL (Dernière Ligne)
Dim PL As Range 'déclare la variable PL (PLage)
Dim PC As Range 'déclare la variable PL (Première Colonne)
Dim I As Long 'déclare la variable I (Incrément)
Dim J As Long 'déclare la variable J (incrément)
Dim K As Long 'déclare la variable J (incrément)
Dim M As Integer 'déclare la variable J (incrément)
Dim N As Integer 'déclare la variable J (incrément)
Dim PCV As Integer 'déclare la variable PCV (Première Colonne Vide)
Dim TV As Variant 'déclare la variable TV (Tableau des Valeurs)
Dim TD() As Variant 'déclare la variable TD (Tableau des Doublons)
Dim R As Range 'déclare la variable R (Recherche)
Dim TMP As Variant 'déclare la variable TMP (TeMPoraire)
Dim PAS As Range 'déclare la variable PAS (Plage à Supprimer))
Application.ScreenUpdating = False 'masque les rafraîchissements d'écran
DEB = Timer 'début du chronométarge
'onglet "Base de données originales" (les dates sont en colonne 4 (= D)
Set OB = Worksheets("Base de données originales") 'définit l'onglet OB
Set D = CreateObject("Scripting.Dictionary") 'définit le dictionnaire D
Set PAS = OB.Range("A1") 'initialise la plage à supprimer PAS
DL = OB.Cells(Application.Rows.Count, "A").End(xlUp).Row 'définit la dernière ligne éditée DL de la colonne A de l'onglet OB
Set PL = OB.Range("A1:Q" & DL) 'définit la plage PL
Set PC = OB.Range("A1:A" & DL) 'définit la plage PL (la première colonne de PL)
TV = PL 'définit le tableau de valeurs TV
For I = DL To 2 Step -1 'boucle inversée sur toutes les lignes I du tableau des valeurs TV (de DL à 2)
If D.exists(TV(I, 1)) Then GoTo suite 'si la donnée ligne I colonne 1 de TV existe dans le dictionnaire D, va à l'étiquette "suite"
D(TV(I, 1)) = "" 'ajoute la donnée ligne I colonne 1 de TV au dictionnaire D
K = 0 'initialise K
If Application.WorksheetFunction.CountIf(PC, TV(I, 1)) > 1 Then 'condition 1 : si le nombre de fois que la donnée ligne I colonne 1 de TV existe dans la plage PC est supérieur à 1
K = K + 1 'incrémente K
ReDim Preserve TD(1 To 2, 1 To K) 'redimensionne le tableau des doublons TD (2 lignes, K colonnes)
TD(1, K) = I 'récupère le numéro de ligne I dans la ligne de TD
TD(2, K) = CLng(DateSerial(Year(TV(I, 4)), Month(TV(I, 4)), Day(TV(I, 4)))) 'récupère la date (en entier long) de la donnée ligne I colonne 4 de TV dans la ligne 2 de TD
Set R = PC.Find(TV(I, 1), OB.Cells(I, 1), , , , xlPrevious, xlValues, xlWhole) 'définit la recherche R (Recherche au-dessous un nouvelle occurrence exacte de la données ligne I colonne 1de TV dans la plage PC)
Do 'exécute
K = K + 1 ' incrémente K
ReDim Preserve TD(1 To 2, 1 To K)
TD(1, K) = R.Row 'récupère le numéro de ligne de la l'occurrence trouvée dans la ligne de TD
TD(2, K) = CLng(DateSerial(Year(PC(R.Row, 4).Value), Month(PC(R.Row, 4).Value), Day(PC(R.Row, 4).Value))) 'récupère la date (en entier long) de l'occurrence trouvée dans la ligne 2 de TD
Set R = PC.FindPrevious(R) 'redéfinit la recherche R (occurrence précédente)
Loop While Not R Is Nothing And R.Row <> I 'boucle tant qu'il existe des occurrence ailleurs que dans la ligne I
'tri selon des dates
For M = 1 To K 'boucle 1 : sur toutes les valeur du tableau des doublons (de 1 à K)
For N = 1 To K 'boucle 2 : sur tous les doublons du tableau TD ( de 1 à K)
If M <> N And TD(2, N) < TD(2, M) Then 'condition 2 : si M est différent de N est les dates sont identiques
TMP = TD(1, M): TD(1, M) = TD(1, N): TD(1, N) = TMP 'tri les numéro de lignes
TMP = TD(2, M): TD(2, M) = TD(2, N): TD(2, N) = TMP 'tri les dates
End If 'fin de la contition 2
Next N 'prochaine valeur N
Next M 'prochaine valeur M
'le tableau des doublons TD est maintenant trié de la date la plus récente à la date la plus ancienne
For M = 2 To K 'boucle sur toutes les valeurs du tableau des doublons (en partant de la seconde, de 2 à K)
PCV = OB.Cells(TD(1, 1), Application.Columns.Count).End(xlToLeft).Column + 1 'définit la première colonne vide PCV de la ligne la plus ancienne
OB.Cells(TD(1, M), "A").Resize(1, 17).Copy OB.Cells(TD(1, 1), PCV) 'copy la cellule ligne TD(1,M) colonne A redimensionné de 17 colonne (soit la plage A:Q de la ligne TD(1,M)) dans le celllule ligne I colonne PCV
Set PAS = IIf(PAS.Cells.Count = 1, OB.Rows(TD(1, M)), Application.Union(PAS, OB.Rows(TD(1, M)))) 'redéfinit la plage à supprimer PAS
Next M 'prochain valeur de la boucle
End If 'fin de la condition 1
suite: 'étiquette
Next I 'prochaine ligne de la boucle 1 (en remontant)
PAS.Delete 'supprime la plage PAS
'tous les autres onglets (les dates sont en colonne 5 (= E)
For Each OB In Sheets 'boucle : sur tous les onglets du classeur
If OB.Name <> "Base de données originales" Then 'condition : si l'onglet ne se nomme pas "Base de données originales"
Set D = CreateObject("Scripting.Dictionary")
Set PAS = OB.Range("A1")
DL = OB.Cells(Application.Rows.Count, "A").End(xlUp).Row
Set PL = OB.Range("A1:Q" & DL)
Set PC = OB.Range("A1:A" & DL)
TV = PL
For I = DL To 2 Step -1
If D.exists(TV(I, 1)) Then GoTo suite2
D(TV(I, 1)) = ""
K = 0
If Application.WorksheetFunction.CountIf(PC, TV(I, 1)) > 1 Then
K = K + 1
ReDim Preserve TD(1 To 2, 1 To K)
TD(1, K) = I
TD(2, K) = CLng(DateSerial(Year(TV(I, 5)), Month(TV(I, 5)), Day(TV(I, 5))))
Set R = PC.Find(TV(I, 1), OB.Cells(I, 1), , , , xlPrevious, xlValues, xlWhole)
Do
K = K + 1
ReDim Preserve TD(1 To 2, 1 To K)
TD(1, K) = R.Row
TD(2, K) = CLng(DateSerial(Year(PC(R.Row, 5).Value), Month(PC(R.Row, 5).Value), Day(PC(R.Row, 5).Value)))
Set R = PC.FindPrevious(R)
Loop While Not R Is Nothing And R.Row <> I
For M = 1 To K
For N = 1 To K
If M <> N And TD(2, N) < TD(2, M) Then
TMP = TD(1, M): TD(1, M) = TD(1, N): TD(1, N) = TMP
TMP = TD(2, M): TD(2, M) = TD(2, N): TD(2, N) = TMP
End If
Next N
Next M
For M = 2 To K
PCV = OB.Cells(TD(1, 1), Application.Columns.Count).End(xlToLeft).Column + 1 'définit la première colonne vide PCV de la ligne la plus ancienne
OB.Cells(TD(1, M), "A").Resize(1, 17).Copy OB.Cells(TD(1, 1), PCV) 'copy la cellule ligne J colonne A redimensionné de 17 colonne (soit la plage A:Q de la ligne J) dans le celllule ligne I colonne PCV
Set PAS = IIf(PAS.Cells.Count = 1, OB.Rows(TD(1, M)), Application.Union(PAS, OB.Rows(TD(1, M))))
Next M
End If
suite2:
Next I
PAS.Delete
End If 'fin de la condition
Next OB 'prochain onglet de la boucle
Application.ScreenUpdating = True 'affiche les rafraîchissements d'écran
MsgBox "Données traitées en " & Timer - DEB & " !" 'message
End Sub