Suppression des doublons dans plage excel

Contenu du snippet

Liminaire :
La méthode
Range.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
proposée par Microsoft pour le traitement des doublons dans une plage d'Excel est pleine de surprises (c'est le moins qu'on puisse dire, si l'on ne veut pas utiliser le mot "bug")
- Elle ne détermine l'existence de doublons qu'à partir de la seconde ligne de la plage, ce qui fait que si la première ligne contient une valeur possédant un doublon, elle "reste". Certains ont pallié cette carence en :
--- créant un entête de colonne, puis en appliquant la méthode à la colonne, depuis cet entête. Bizarre, de forcer à une telle création si l'on veut un fonctionnement clair ! Et quid si l'on ne veut pas traiter les doublons depuis le début (entête inclus) d'une colonne, mais dans une portion de la colonne ? Je ne crois personnellement à ce propos pas que Microsoft avait prévu l'existence obligatoire d'un entête (il n'en parle d'ailleurs pas dans l'exposé de sa méthode), mais qu'il s'agit tout simplement d'un bug !
--- les doublons ne sont pas supprimés, mais les lignes qui les contiennent sont simplement masquées
J'ouvre à ce propos une petite parenthèse. Lorsque la méthode de Microsoft est adoptée "sur place" (xlFilterInPlace) les doublons de la première plage sont masqués (pas supprimés) ! Oh ! Que répond Microsoft en ce qui concerne cet aspect pour le moins inattendu ? Tenez-vous bien : pour les ré-afficher, il "suffit" de ré-afficher dans la première plage les lignes masquées ! Elle est bien bonne, celle-là ! (obliger à "rétablir" - et comment, pour le cas où existeraient, avant traitement, des lignes masquées, distinguer celles-ci de celles masquées par la méthode ? c'est un vrai "foutage de gueule !)

Existe bien évidemment la possibilité de se passer de cette méthode et traiter autrement, mais, si on veut une action rapide, il sera alors nécessaire de trier d'abord la plage concernée, puis de faire une boucle. Mais quid si l'utilisateur veut à la fois éviter ce tri et éviter également une boucle plus longue (utilisant en plus Find) pour repérer les doublons ? Il lui faudra alors utiliser la méthode AdvancedFilter, mais voilà : avec les inconvénients dénoncés, si on ne la "corrige" pas !

CORRIGER sera le maître terme de la suite.
La procédure que je propose permet :

- d'utiliser l'essentiel de la méthode AdvancedFilter
- de traiter la plage effectivement concernée (on n'a pas à ser préoccuper d'autre chose), qu'elle commence ou non en début d'une colonne
- de (à son gré) supprimer ou simplement masquer les doublons
- si l'on décide de supprimer les doublons, mais que l'une des lignes dont on recherche les doublons (eux-mêmes masqués ou non) était elle-même masquée : supprimer ses doublons mais laisser masquée la ligne en cause.

Voilà en gros l'exposé.

Passons à la procédure elle-même, à mettre dans un module :
1) en voici le code :

Source / Exemple :


Option Explicit

Public Sub supp_doublons(x As Range, methode As Boolean)
' ATTENTION :
' ce code est libre d'utilisation et de divulgation sur d'autres sites
' seule obligation : y inclure la mention suivante :
'***************************************************************************************
' code provenant de Codes-Sources (Forum VBFRANCE) - Auteur : ucfoutu
'***************************************************************************************
    Dim c As Range, z As Range, ae As Range, cp As Range, nc As Long, ntr As Long
    Application.ScreenUpdating = False
 With x.Worksheet
    .Rows(x.Row).Insert Shift:=xlUp
    .Cells(x.Row - 1, x.Column).Value = Chr(1)
    ' non ! je ne fais fas ici l'économie de limiter le range à la dernière cellule remplie
    ' l'utilisateur pourrait en effet décider (c'est son droit) de traiter l'ensemble de la plage
    ' et y supprimer (avec le paramètre True) certaines lignes vides en doublons (cachées ou non)
    Set z = .Range(.Cells(x.Row - 1, x.Column), .Cells(x.Rows.Count + x.Row, x.Column))
    ntr = 0
    For Each c In z.Rows
      If c.Hidden = True Then
        If cp Is Nothing Then Set cp = c Else Set cp = Application.Union(cp, c)
        ntr = ntr + 1
        If ntr >= nc Then Exit For ' on ne  continue pas pour rien !
      End If
    Next
    If Not cp Is Nothing Then cp.Rows.Hidden = False
    z.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
    DoEvents
    If methode Then
      nc = z.Rows.Count - z.Rows.SpecialCells(xlCellTypeVisible).Count
      ntr = 0
      For Each c In z.Rows
        If c.Hidden = True Then
          If ae Is Nothing Then Set ae = c Else Set ae = Application.Union(ae, c)
          ntr = ntr + 1
          If ntr >= nc Then Exit For 'on ne continue pas pour rien
        End If
      Next c
    End If
    If Not cp Is Nothing Then cp.Rows.Hidden = True
    If methode And Not ae Is Nothing Then ae.EntireRow.Delete
    .Cells(x.Row - 1, x.Column).EntireRow.Delete
  End With
  Set z = Nothing: Set ae = Nothing: Set cp = Nothing
  Application.ScreenUpdating = True
End Sub

Conclusion :


2) voila comment l'appeler (depuis où l'on veut), avec les explications nécessaires en ce qui concerne les paramètres à lui passer

supp_doublons Plage, methode_de_traitement
où :
a)====>> Plage est le "range" à traiter, comportant le nom de la feuille qui le contient, dans la notation que l'on veut.
Exemlples :
Sheets(4).Range("B5:B10")
Sheets("Feuil4").Range(Cells(5, 2), Cells(10, 2))
etc....
b) =====>> methode_de_traitement est une booléenne (True ou False)
----- si False : ===>> seule chaque première (dans l'ordre) valeur est conservée intacte (masquée ou non). Tous ses doublons sont masqués. Si une première valeur est elle-même masquée, elle le reste.
----- Si True : Seule chaque première valeur est conservée (dans son état masqué ou non). Tous ses doublons sont supprimés.

Comme on le voit, cette procédure est flexible et respecte "l'état des lieux"

Exemple d'appel complet :

supp_doublons Sheets(4).Range("A5:A10"), True

Mon commentaire ;
1) je ne maîtrise pas parfaitement VBA/Excel (j'estime n'en être qu'aux balbutiements) et ne suis donc pas certain de ce que, malgré mes efforts (5 moutures ont précédé la présente), elle ne puisse pas être encore plus optimisée
Je n'ai toutefois pas classé ce "source" dans la catégorie "débutant", car je sais que ce n'est pas du niveau débutant....
2) J'y ai ajouté un commentaire relatif à une mention à ajouter si l'on utilise ce code (que l'on ne trouve nulle part ailleurs sur le Web), non pour empoisonner l'existence, mais pour éviter (hélàs trop souvent observé) que des lascars ne le déposent à leur tour sur d'autres sites sans en préciser la provenance (je n'aime pas çà !)
3) Comme je l'ai dit, j'en suis encore à tâtonner sous VBA/Excel. Si d'autres forumeurs, plus avancés que moi, y "mettaient leur grain de sel" pour proposer une amélioration ou une optimisation, ils seront bien évidemment les bienvenus
4) Ce n'est qu'après vos comment aires que je m'attaquerai à la phase 2 : utiliser (selon ce même principe général) la méthode AdvancedFilter et Unique = True, mais pour créer une autre plage sans doublons (xlFilterCopy), sans toucher à la plage d'origine (pardi ...)
Amitiés

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.