1

The below code is used to hide the visible duplicate cells (rows).
It works , But If I later used autofiletr on any column then all the hidden rows are shown again.
My aim is to use a helper column and set filter on value e,g (False).
In advance, thanks for any help.

Function Hide_visible_duplicate_cells(procRng As Range)
 
    Dim arng As Range, rngU As Range, C As Range, dict As New Scripting.Dictionary
 
    Set arng = procRng.SpecialCells(xlCellTypeVisible)
 
    If arng Is Nothing Then MsgBox "Not a valid Range": Exit Function
 
    For Each C In arng.Cells
        If Not dict.Exists(C.value) Then
            dict.Add C.value, vbNullString       'Keep the first occurrence
        Else
          If rngU Is Nothing Then                'Create a Union range for the next occurrences:
             Set rngU = C
          Else
             Set rngU = Union(rngU, C)
          End If
        End If
    Next C
 
   If Not rngU Is Nothing Then rngU.EntireRow.Hidden = True    'Hide the rows at once
 
End Function
Eugene Astafiev
  • 47,483
  • 3
  • 24
  • 45
Waleed
  • 847
  • 1
  • 4
  • 18
  • I would like you to clarify the next issue: Your actual function processes `procRng` range. If it is a selection, part of a larger range but **not containing columns headers**, using the filtering will be difficult. So, will you take care that the respective range is able to be filtered (in the normal way)? – FaneDuru Mar 08 '23 at 08:03
  • @FaneDuru ,It seems I will stick with your function on the linked question – Waleed Mar 08 '23 at 09:30
  • I already prepared a solution, but you should should define/select the range including the header on which the filtering to be done. I will post it in 2, 3 minutes. No need to accept it if you do not need it. I do not need it, neither... – FaneDuru Mar 08 '23 at 09:34
  • Sure I need it. The answer has some issues and I will cite later. – Waleed Mar 08 '23 at 12:42

2 Answers2

1

Please, try the next way. But you need to use the column range which you need to be processed, taking care that its first row to be the column headers one:

Sub Hide_visible_duplicate_cells_(procRng As Range)
    Dim arng As Range, C As Range, dict As New Scripting.Dictionary
    Dim arrMark, colMark As Range, lastC As Long, sh As Worksheet, lastR As Long, i As Long
    
    Const markName As String = "Marker_column"
    
    Set arng = procRng.SpecialCells(xlCellTypeVisible)
    
    If arng Is Nothing Then MsgBox "Not a valid Range": Exit Sub
    
    Set sh = procRng.Parent 'the sheet where the range belongs to

    lastR = sh.UsedRange.rows(sh.UsedRange.rows.count).row  'last row OF THE SHEET
    ReDim arrMark(1 To lastR, 1 To 1) 'redim the markers array
    
    'determinte the column where the marker to be placed (or it already exists):
    Set colMark = sh.rows(procRng.cells(1).row).Find(What:=markName, LookIn:=xlValues, LookAt:=xlWhole)
    If Not colMark Is Nothing Then
        lastC = colMark.column  'for the case when the marker column exists
    Else
        lastC = sh.cells(procRng.cells(1).row, sh.Columns.count).End(xlToLeft).column + 1 'next empty column if marker column does not exist
        'to correct the last column number, IF LAST COLUMN IS HIDDEN (it MUST HAVE A HEADER):
        If sh.cells(procRng.cells(1).row, lastC).Value <> "" Then lastC = lastC + 1
    End If
    
    For Each C In arng.cells
        If Not dict.Exists(C.Value) Then
            If i > 0 Then                                            'to skip the first cell, which should be on the headers row
                dict.Add C.Value, vbNullString       'Keep the first occurrence
                arrMark(C.row - procRng.cells(1).row, 1) = "True"      'place the marker for the first occurrence
            End If
            If C.Value <> "" Then i = i + 1 'for the case of empty cells above the header...
        End If
    Next C
    'place the marker column header, if not already existing:
     If colMark Is Nothing Then sh.cells(procRng.cells(1).row, lastC).Value = markName 'place the marker column name, IF NOT EXISTS
     
    If sh.AutoFilterMode Then sh.AutoFilterMode = False  'eliminate the filter, if any
    
    'drop the markers array content:
    sh.cells(procRng.cells(1).row + 1, lastC).Resize(UBound(arrMark), 1).Value2 = arrMark
    
    'filter by the marker column
    sh.Range(sh.cells(procRng.cells(1).row, 1), sh.cells(sh.UsedRange.rows.count, lastC)).AutoFilter lastC, "True"
End Sub
FaneDuru
  • 38,298
  • 4
  • 19
  • 27
  • My header row is the second row (I had to delete the first row to test your answer), So I think it’s better to make it (header row) a **constant** at beginning of code to be easily adaptable. Also, `Const markName` is not created on the header row (I found it on the third row). And each time I run the code, the `marker column` is added again , I prefer to adapt the code to find the marker column by using `Const markName` . – Waleed Mar 08 '23 at 12:57
  • @Waleed What range did you send to the above sub? Does it start with the second row? IF yes, it should work as you need. Can you write what (exactly) range (address) do you send to the `Sub`? I am not near my computer, but I am in a different location with access to internet... Is it a single column range? For instance, if you sent the range "J2:J100" it would understand that the header is on the second row, which will be skipped from processing and used for adding the marker column name. Is anything unclear in what I say? – FaneDuru Mar 08 '23 at 13:52
  • @Waleed If the header would be on the fifth row and **you will build the range as "A5:a200", it will work as you need**... – FaneDuru Mar 08 '23 at 14:01
  • You are correct, I was passing the range in a wrong way – Waleed Mar 08 '23 at 15:23
  • Driving now... Doesn't it set the header on the second row using the suggested way? I can adapt something only after I will be at home. – FaneDuru Mar 08 '23 at 15:25
  • @Waleed Please, use the updated answer. It has only a code line changed. The one calculating `lastR`. If you run the code first time, it will work correctly with existing, but if you run it more time and the last sheet row is the single visible one from a category it will have `TRUE` boolean value **which will not be overwritten in case of a new range not involving this last row**. `arrMark` will be `ReDim` to have **less rows than maximum possible and what exceeds its `UBound` will remain as they are and be used by the filter to wrongly return them**... – FaneDuru Mar 08 '23 at 19:26
  • It works perfectly. **But,** there is an issue and you already created a good code for it [Link](https://stackoverflow.com/questions/75398341/get-the-last-column-number-while-the-column-is-hidden) If the last column is hidden then `Marker_column` will overwrite it. – Waleed Mar 09 '23 at 05:54
  • I will adapt the code when I will be near my computer. – FaneDuru Mar 09 '23 at 08:44
  • @Waleed I made some tests and I am afraid that neither `Find` is not able to find the last hidden column **if the range is filtered**. It is not able to find the column before the hidden one. It returns 1... Is your range to be processed filtered? – FaneDuru Mar 09 '23 at 10:56
  • yes the processed range is filtered. I found out If filter is applied then `Find` returns the number -1. I will show the hidden column to give peace to my mind. – Waleed Mar 09 '23 at 11:32
  • @Waleed If you had such unusual habit to hide the last column, **you should state it in your question**. I would check if I will be able to find a solution for such a case, but you did not. Since, you know how much I care about notoriety point, unaccepting is not an issue, from this point of view. But I consider that I answered your question **as it was formulated**. I have an idea about doing something to help, but in such circumstances I lost my enthusiasm to do something. Even if you will reaccept the answer... – FaneDuru Mar 09 '23 at 12:47
  • Please, What is the idea you mentioned yesterday ? – Waleed Mar 10 '23 at 13:42
  • @Waleed Like I said, I lost my enthusiasm and I didn't even try it. In principle, I was intending to extract last column in the classical I used in the above code and check if the next column has a header. But checking on the sheet reference, not on the range... If it has, this means that a header exists and `lactC` should be incremented. I will try now a rapid check. I think it should work... – FaneDuru Mar 10 '23 at 14:36
  • 1
    @Waleed Adapted the code in the way I suggested above. Also adapted the last code line to make it working even if you have some garbage above the second row. – FaneDuru Mar 10 '23 at 14:46
  • AutoFilter has been fixed , But the problem of getting last column (if is hidden) still as it is) `markName` overwrite it. Anyhow you exerted many efforts in this question . I will use your **wonderful code** [LINK](https://stackoverflow.com/questions/75398341/get-the-last-column-number-while-the-column-is-hidden) and try to adapt it to check either `Filtermode` is used or not . – Waleed Mar 10 '23 at 14:58
  • @Waleed Does the last hidden column **have a header**, as I suggested? If it has, the code should work. If not, and you insist to not place a header there, it does not... – FaneDuru Mar 10 '23 at 15:01
  • Yes it has a header on the second row. – Waleed Mar 10 '23 at 15:10
  • I am driving... – FaneDuru Mar 10 '23 at 15:15
  • 1
    @Waleed I checked the code only once and it works. I checked it now several times and it worked as it should. But when looked to the place where I copied the code line I was talking about in my previous comments, I observed that I copied in a wrong place. It should be acting only if the marker column has not been found, but it was placed above (when marker column exists... If you check it now, I am sure that it will work for you, too. – FaneDuru Mar 10 '23 at 19:34
  • Now all works perfectly – Waleed Mar 11 '23 at 06:00
  • 1
    I replaced `LookIn:=xlValues` with `LookIn:=xlFormulas` and now it finds `colMark` more properly **even it exists and hidden or filtered** . Do you have any explanation ? – Waleed Mar 13 '23 at 09:13
  • 1
    @Waleed But I always used `xlFormulas`... I tried determining the last row, about I read that `xlValues` should be used and probably I copied from one of that trials. Good to know that it works as it should, even in filtered ranges. – FaneDuru Mar 13 '23 at 10:25
  • @Waleed Some minutes ago I found here a comment from you with a link to a question which now is deleted... I looked at it and I made some tests. I think I have an idea, if I correctly understood the question. When tried to ask for clarifications, I found it deleted. What's happening? Did you find the solution? I think the code was more complicated than it should be. Of course, if I correctly understood the question. Besides the hidden columns, where there hidden rows, too? Then, if always the mentioned columns should be processed, why to place them in a selection? – FaneDuru Mar 14 '23 at 13:50
  • I deleted myself because someone voted to close it. I agree with you that my code is complicated (sorry). I found that I can export also column `"L"` , then processing it on the new workbook . you may already prepared a code, so I will open again. – Waleed Mar 14 '23 at 14:01
  • @Waleed Like I said, I made some tests and I have the solution (in my head...). No need to import column "L"... I tested how to use `Offset` of the last cell on each discontinuous range rows... – FaneDuru Mar 14 '23 at 14:05
  • @Waleed I think you just can undelete it... Maybe, it would be good to also paste a picture with the data to be processed. – FaneDuru Mar 14 '23 at 14:14
  • the `Selection` is random , it can be any cell on the row(s) ( continuous or non-continuous) .the posted code is fully reproduceable and can be tested. If it is still unclear, please let me know to delete and post a new question. – Waleed Mar 14 '23 at 14:25
  • @Waleed I already finalized a version (tested) according to my way of understanding, but I think it should fit yours. I will place an answer in two minutes, then I need to go out for some minutes... – FaneDuru Mar 14 '23 at 14:27
  • **Mr.FaneDuru** , your answer works perfectly with me, I am just curious is the same result could be achieved without using a helper column by using your splendid way (Dictionary+Arrays)? if the answer is yes kindly advice me to ask a new question here or on Code Review ? – Waleed Jun 10 '23 at 11:02
  • I tried my own attempt and now I am quite sure that this task is impossible to be completed without using a helper column. – Waleed Jun 10 '23 at 12:26
  • @Waleed So it looks, because of the fact that it should hide duplicates. So, it looks that it is not possible to use a filter able **to let unique cases visible**. I think it can be also done filtering by an array. Of course, using some tricks... – FaneDuru Jun 10 '23 at 13:10
  • Is it possible to put the address of unique cells in an array and then use that array as the criteria of AutoFilter? I know you like challenging. – Waleed Jun 10 '23 at 13:43
  • @Waleed Not exactly... Loading the dictionary in a different way and use its (modified) items. I have the solution in my head. And I think it should be working... Now I have something to do in my yard, but if you place a question asking about such an issue I will try answering it when I will be back to my computer. No more then an hour staying outside. If somebody else will answer it, even better, I will also place my answer after that. – FaneDuru Jun 10 '23 at 13:46
  • Ok enjoy your time, anyhow I think the available answer is to hide the duplicate cells which will be broken by a subsequent filter and I don't like that. – Waleed Jun 10 '23 at 15:08
  • @Waleed Don't you need filtering the existing filtered column? If yes, nothing wrong should be happening. And you will learn a different approach to solve such an issue. If not interested, I do not have any problem. Solution will remain in my head. – FaneDuru Jun 10 '23 at 15:43
  • Mr.FaneDure , you always surprise me with new programming tricks, and this time I am very eager to see your answer , kindly see this question [Link](https://stackoverflow.com/questions/76449222/hide-duplicate-cells-without-using-a-helper-column) – Waleed Jun 11 '23 at 06:14
0

You can easily create such helper column with a formula. Put the following formula into your helper column. The example assumes that the values that needs to be checked for duplicates are in column A and that your data starts in row 2.

=COUNTIF(A$1:A2,A2)=1

enter image description here

(Note that on my computer the parameter separator is a semicolon)

Update

if you want to write this value via VBA:

If Not dict.Exists(C.value) Then
    dict.Add C.value, vbNullString       ' Keep the first occurrence
    C.Offset(0, 1).value = True          ' Signal: This is the first occurrence
Else
    C.Offset(0, 1).value = False
    (...)

You just need to adapt the Offset so that the data is written into the correct column.

FunThomas
  • 23,043
  • 3
  • 18
  • 34