2010-01-29 7 views
0

Je travaille sur une procédure dans Excel en utilisant VBA qui met en évidence les lignes en double. La procédure évalue le résultat de la fonction de feuille de calcul sumproduct pour déterminer si la ligne a des doublons.Est-il possible d'exclure des lignes cachées lors de la recherche de doublons dans Excel?

La formule se termine évalué par ressembler à ceci:

SUMPRODUCT(--(A1:A10 = A1), --(B1:B10 = B1), --(C1:C10 = C1)) 

Jusqu'à présent, la procédure fonctionne très bien, mais je dois à ne pas tenir compte des lignes et des colonnes masquées de l'évaluation. Je peux ignorer les lignes cachées dans les colonnes de mes boucles en utilisant Range.Hidden = False, mais je n'ai pas trouvé un moyen d'exclure les lignes et les colonnes cachées de SUMPRODUCT.

J'ai aussi essayé itérer chaque ligne en utilisant deux fois deux boucles imbriquées et juste comparer les valeurs de deux lignes à la fois, mais qui a donné lieu à N-carré, ou O (n), itérations, donc je donne sur cette méthode.

Existe-t-il un moyen de contraindre SUMPRODUCT à ignorer les lignes cachées, comme cela est possible avec la formule de feuille de calcul SUBTOTAL?

Voici ce que j'ai jusqu'à présent utilisé Evaluate(SUMPRODUCT): Merci!

Private Sub ShowDuplicateRows() 

    Dim lngRow As Long 
    Dim lngColumn As Long 
    Dim strFormula As String 

    With Selection 

     For lngRow = 1 To .Rows.Count 
      If Not .Rows(lngRow).Hidden Then 

       strFormula = "SUMPRODUCT(" 
       For lngColumn = 1 To .Columns.Count 
        If Not .Columns(lngColumn).Hidden Then 
         If strFormula <> "SUMPRODUCT(" Then 
          strFormula = strFormula & ", " 
         End If 
         strFormula = strFormula _ 
         & "--(" & .Columns(lngColumn).Address _ 
         & " = " & .Cells(lngRow, lngColumn).Address & ")" 
        End If 
       Next 
       strFormula = strFormula & ")" 

       If Evaluate(strFormula) > 1 Then 
        .Rows(lngRow).Font.Color = RGB(255, 0, 0) 
       End If 

      End If 
     Next lngRow 

    End With 

End Sub 

Répondre

1

La propriété RowHeight/Hidden n'est exposée à aucune formule. La solution devra être en VBA. Une façon d'y parvenir est de créer une formule définie par l'utilisateur (UDF) qui fait ce que vous voulez, puis l'utiliser dans votre formule sumproduct.

Public Function IsVisible(ByVal rng As Excel.Range) As Variant 
    Dim varRtnVal As Variant 
    Dim lRow As Long, lCol As Long 
    Dim ws As Excel.Worksheet 
    ReDim varRtnVal(1 To rng.Rows.Count, 1 To rng.Columns.Count) 
    For lRow = 1& To rng.Rows.Count 
     For lCol = 1& To rng.Columns.Count 
      varRtnVal(lRow, lCol) = CDbl(-(rng.Cells(lRow, lCol).RowHeight > 0&)) 
     Next 
    Next 
    IsVisible = varRtnVal 
End Function 

Ensuite, votre formule ressemblerait à ceci:

=SUMPRODUCT(IsVisible($A$2:$A$11),--($A$2:$A$11=1),--($B$2:$B$11=1),--($C$2:$C$11=1)) 
+0

Spooky. Je m'étais déjà engagé dans cette voie avant de revenir sur ce sujet. L'UDF que j'ai écrit est presque identique au vôtre. Quelle est la signification du "&" dans 1 & et 0 &? – Kuyenda

+0

C'est un caractère de déclaration de type, il force le littéral "1" au type Long. Si vous ne les mettez pas sur vos littéraux, VBA lui donnera le plus petit nombre entier, long ou double. Comme le type natif de VB est long, toutes les instructions (telles que Redim/For etc.) sont longues (d'où les 1). De plus, la comparaison doit passer par la conversion implicite aux mêmes types. Donc comme la hauteur de la ligne est longue, je l'ai ajouté au 0, donc il n'aurait pas à subir de conversion implicite. C'est la micro-optimisation et ne fera probablement aucune différence mesurable. C'est seulement l'habitude et le style personnel. La seule fois c'est ... – Oorang

+0

important de taper des littéraux est quand vous utilisez des constantes hexadécimales ou octales et ils ne sont pas signés, et ainsi VBA n'effectue pas la conversion correctement lorsque les nombres sont dans certaines fourchettes (2^16 spécifiquement: http://support.microsoft.com/kb/38888). Pour résumer, vous n'avez pas vraiment besoin d'eux, je les ai juste mis là :) – Oorang

0

Ceci est le code complet mis à jour. D'abord la procédure principale, puis la fonction définie par l'utilisateur.

Si quelqu'un peut expliquer pourquoi mettre la boucle imbriquée dans un UDF est plus rapide que de l'avoir dans la procédure principale, je l'apprécierais grandement! Merci encore à Oorang!

J'ai rendu ma version de l'UDF IsVisible un peu plus flexible. Il peut utiliser une plage passée en paramètre ou, si aucune n'est passée, utilise Application.Caller.

Private Sub ShowDuplicateRows() 

    Dim lngRow As Long 
    Dim lngColumn As Long 
    Dim strFormula As String 

    With Selection 

     For lngRow = 1 To .Rows.Count 
      If Not .Rows(lngRow).Hidden Then 

       strFormula = "SUMPRODUCT(--(ISVISIBLE(" _ 
       & .Columns(1).Address & "))" 
       For lngColumn = 1 To .Columns.Count 
        If Not .Columns(lngColumn).Hidden Then 
         strFormula = strFormula _ 
         & ", --(" & .Columns(lngColumn).Address _ 
         & " = " & .Cells(lngRow, lngColumn).Address & ")" 
        End If 
       Next 
       strFormula = strFormula & ")" 

       If Evaluate(strFormula) > 1 Then 
        .Rows(lngRow).Font.Color = RGB(255, 0, 0) 
       Else 
        .Rows(lngRow).Font.ColorIndex = xlAutomatic 
       End If 

      End If 
     Next lngRow 

    End With 

End Sub 

Public Function IsVisible(Optional ByVal Reference As Range) As Variant 

    Dim varArray() As Variant 
    Dim lngRow As Long 
    Dim lngColumn As Long 

    If Reference Is Nothing Then Set Reference = Application.Caller 

    With Reference 

     ReDim varArray(1 To .Rows.Count, 1 To .Columns.Count) 

     For lngRow = 1 To .Rows.Count 
      For lngColumn = 1 To .Columns.Count 
       varArray(lngRow, lngColumn) _ 
       = Not .Rows(lngRow).Hidden _ 
       And Not .Columns(lngColumn).Hidden 
      Next lngColumn 
     Next lngRow 

    End With 

    IsVisible = varArray 

End Function 
Questions connexes