Suppression des doublons dans plage excel

Soyez le premier à donner votre avis sur cette source.

Snippet vu 9 606 fois - Téléchargée 17 fois

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

Ajouter un commentaire

Commentaires

Messages postés
40
Date d'inscription
mercredi 14 mai 2008
Statut
Membre
Dernière intervention
16 octobre 2012

je m'interesse a vba mais là beaucoup de chose sont encore confus , je vais prendre le temps....
Messages postés
6
Date d'inscription
samedi 10 novembre 2007
Statut
Membre
Dernière intervention
14 février 2010

Bonjour
Je suis un débutant en VBA
Voila j’ai un classeur Nome FACTURE Excel(V.2003)
Je suis sur une Feuil C
Je voudrais effacer les contenues de touts les cellules
Non Protéger d’un tableau dans la Feuil A
J’ai utiliser une boucle
Fro i=1 to Sheets.Count
Sheets(i).cells.Clear
Next i
Mais elle ne fonctionne pas
La boucle efface tout la feuil A
Messages postés
18038
Date d'inscription
lundi 7 décembre 2009
Statut
Modérateur
Dernière intervention
11 avril 2018
229
Merci SEMLALI_OS, mais attends que ce soit complet (déjà fait, mais en cours d'optimisation).
Messages postés
9
Date d'inscription
dimanche 25 septembre 2005
Statut
Membre
Dernière intervention
5 novembre 2012

merci pour ton effort
Messages postés
18038
Date d'inscription
lundi 7 décembre 2009
Statut
Modérateur
Dernière intervention
11 avril 2018
229
Ma procédure n'exclut pas la présence d'un Header. S'il est là (parce que voulu) , il l'est (et ma procédure ne s'en trouve pas gênée)... s'il n'est pas là (parce que non estimé utile dans telle ou telle autre appli), il n'est pas là (et ma procédure ne s'en trouve pas plus mal). Je me fiche des démérites ou des mérites d'un header : je n'accepte cependant pas qu'on force à l'utiliser (et une autre fois : quid dans le cas d'une portion de colonne ?)
Si, toi, tu veux rester soumis à cette présence de header, si en plus, lorsque tu utilises la méthode telle qu'elle est pour copier ailleurs et sans doublons, tu te retrouves avec le header dans ta liste de traitement et que cela te plait (y compris de refaire un travail pour exclure le header de ta liste traitée), c'est ton affaire. D'autres, voient différemment et ils sont nombreux.... Microsoft verra bien s'il convient ou non de les satisfaire et dans quelles conditions le faire. J'observe enfin que la version Excel est dotée d'une méthode (que j'ai signalée plus haut) permettant de supprimer les doublons d'une plage. Que c'est curieux, tiens... celle-là, plus longuement réfléchie probablement, n'inclut pas le header, pardi ... Elle traite LA plage concernée et ne dépend pas (logique) de quoi que ce soit d'autre.
Je continue donc allègrement sur ma lancée.... et ce : pour mille et une raisons.
Les multi-colonnes ? c'est maintenant fait sur ma machine (et fera l'objet d'une modif de rien du tout).
La vitesse ? Permets-moi de te faire remarquer que si tu choisis de mettre à False le booléen methode, la seule différence de traitement est l'ajout puis la suppression d'une ligne (et rien d'autre) ! différence de temps d'exécution dans ce cas ? une fraction de seconde.
Un temps légèrement plus long avec methode à True, mais avec la flexibilité que j'ai signalée (relis) dans le vrai respect de ce que veut faire le développeur, sans l'obliger à des acrobaties diverses (voire manuelle) en cas de non satisfaction.
On passe à autre chose ?... (tu as des suggestions d'optimisation du code ?)
Afficher les 16 commentaires

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.