Hello world,
This is my first post, please let me know if my question is not clear.
I am trying to write a macro to find duplicated in column F, see if they have matching values for column O and then delete all rows except for the one that has the longest string in column B.
I think I need to do the following (starting with value in F1 and finishing at the end of the column):
1) Look for duplicates in all column F
2) For each duplicate: check if values in column O are also duplicates
3) If the values in column O are duplicates, then delete all rows except for the one that has the most data in column B.
I am not sure how I should start writing a solution for this.
I know I can use the =LEN() function to check the number of characters in a cell.
However, I am not sure how to pass on the cell references of the duplicates in F so that I can search for duplicates in O. Once I have those references I can pass them on to check for the length of the strings in column B as well.
Then, to delete the rows would I use the row reference and EntireRow.Delete?
I have attached a spreadsheet with an example of what I am trying to achieve.
I have been browsing the forums for a long time but have never asked a question before.
Thanks for your help.
Last edited by vzc8; 06-28-2011 at 11:33 AM.
What happens if the rows to be deleted in "B" have text of the same length ???
Thanks for the quick reply MickG.
Sorry, I forgot to say: If the values in column B are the same then delete all duplicates.
What I realy meant was, if there were 3 duplicates in "B", the length of data in one cell was 3, and the other two where 6, which cell wants deleting.
Thanks again MickG.
Let's say the following rows have identical values in column F and O and have the following in column B:
1 ABCDEF
2 ABCDEF
3 ABC
Then row 2 (ABCDEF) and row 3 (ABC) should be deleted and row 1 (the first in the list of duplicates and the one with the longest, or one of the longest, values in B) should be saved.
Does that make sense, I am not sure if I am explaining myself so well or if what I am trying to do is even possible.
I really appreciate your help though.
Thanks.
Try this:-
I've amended the code I produced yesterday, as I don't think it was correct !!
Regards MickSub MG30Jun58 Dim Rng As Range Dim Dn As Range Dim Twn As String Dim oMax As Integer Dim Rw As Range Dim nRng As Range Dim temp As Range Dim K Set Rng = Range(Range("F1"), Range("F" & rows.count).End(xlUp)) With CreateObject("scripting.dictionary") .CompareMode = vbTextCompare For Each Dn In Rng If Dn.value = Dn.Offset(, 9) Then If Not .Exists(Dn.value) Then .Add Dn.value, Dn.Offset(, -4) Else Set .Item(Dn.value) = Union(.Item(Dn.value), Dn.Offset(, -4)) End If End If Next Dn For Each K In .keys oMax = 0 For Each Rw In .Item(K) oMax = Application.max(Len(Rw), oMax) If Len(Rw) = oMax Then Set temp = Rw Next Rw For Each Rw In .Item(K) If Not Rw.Address = temp.Address Then If .Item(K).count > 1 Then If nRng Is Nothing Then Set nRng = Rw Else Set nRng = Union(nRng, Rw) End If Else If nRng Is Nothing Then Set nRng = Rw Else Set nRng = Union(nRng, Rw) End If End If End If Next Rw Next K End With nRng.EntireRow.Delete End Sub
Last edited by MickG; 06-30-2011 at 06:06 AM.
MickG,
Thanks, your help has been great.
I have been looking at your code and trying to understand it, but unfortunately I do not understand it all. I am learning how to program macros, but some of this has got me confused.
The first version you uploaded did delete rows in case of duplicates, but it seems to have been looking for duplicates in column B and then deleting everything else (see example attached).
The edited code is causing "Error 91 Object Variable or With block variable not set", I am not sure why, when I click debug it highlights the penultimate line: nRng.EntireRow.Delete
With the old version it was almost working correctly, but in some cases it seems to delete rows even when it should now.
In rows 12 & 13 (see attached file), the old macro deleted both rows, but should in fact keep the one with the longest value in column B.
So:
12333 | RG | 622e76m00007
12334455 | RG | 622e76m00007
should turn into:
12334455 | RG | 622e76m00007
I have attached a new file of examples and have included the macro that is causing the 91 error. The macro has been called "TidyUpExtract".
"upload(30Jul11_fortesting).xls" is the file that contains the original data and "upload(30Jul11_examples).xls" contains the data with both the old macro output and the intended output.
Thanks again for any help that you can offer.
Hi, This is the result of Modified code below.
NB:- In your previous thread you said that if any sets of cells for deletion in column "B" had values of the same length and also had the longest lengths, then remove all except one of them, That what my codes does , but you results show more than one.
As in 1234567890 which My code returns 2 and your 3.
New Code:-Row No Col(A) Col(B) Col(C) Col(D) Col(E) Col(F) Col(G) Col(H) Col(I) Col(J) Col(K) Col(L) Col(M) Col(N) Col(O) 1. Require result 2. 12345 12345 DLM 622e76m0000j 3. 1234567890 12345 FRA 621e76l0000c 4. 123456 1234567890 HOR 623e76n000gw 5. 1234 123456 JOHNS 622e76m000ma 6. 987654321 1234 MA 622e76d0000b 7. 987654321 1234567890 MA 622e76d0000h 8. 987654321 1234567890 MA 622e76d00010 9. 1234567890 987654321 MCV 622e76m0000j 10. 12334455 987654321 RG 622e76m00007 11. 987654321 12. 12334455
Regards MickSub MG30Jun57 Dim Rng As Range Dim Dn As Range Dim Twn As String Dim oMax As Integer Dim Rw As Range Dim nRng As Range Dim temp As Range Dim K Set Rng = Range(Range("F1"), Range("F" & Rows.Count).End(xlUp)) With CreateObject("scripting.dictionary") .CompareMode = vbTextCompare For Each Dn In Rng If Application.CountIf(Rng.Offset(, 9), Dn.Offset(, 9)) > 1 Then If Not .Exists(Dn.Value) Then .Add Dn.Value, Dn.Offset(, -4) Else Set .Item(Dn.Value) = Union(.Item(Dn.Value), Dn.Offset(, -4)) End If End If Next Dn For Each K In .keys oMax = 0 For Each Rw In .Item(K) oMax = Application.Max(Len(Rw), oMax) If Len(Rw) = oMax Then Set temp = Rw Next Rw For Each Rw In .Item(K) If Not Rw.Address = temp.Address Then If .Item(K).Count > 1 Then If nRng Is Nothing Then Set nRng = Rw Else Set nRng = Union(nRng, Rw) End If Else If nRng Is Nothing Then Set nRng = Rw Else Set nRng = Union(nRng, Rw) End If End If End If Next Rw Next K End With 'nRng.Interior.ColorIndex = 6 'MsgBox nRng.Address nRng.EntireRow.Delete End Sub
Last edited by MickG; 06-30-2011 at 12:08 PM.
MickG: Thank you very much!
So far I think it is a 100% fit for what I am trying to accomplish. I was testing it yesterday and meant to reply but ran out of time, sorry about that.
I am impressed with you quick reply and really appreciate you help. I am still learning to program macros, and have to admit that I could never have written this on my own.
Thanks for posting this solution, I will try to learn as much as I can from studying this code.
Thank you for your kind responses, they are much appreciated
Regards Mick
Hello again,
Sorry, but I have a follow-up question. After running the code above I need to go back, inspect the file and then clean for values in F that have an identical value in B.
So:
B F
1234 ABCD
12345 ABCDE
123 ABCD
123 ABCD
1234 ABCD
Should become:
B F
1234 ABCD
12345 ABCDE
123 ABCD
I took the code you wrote above and edited only a minor part:
Is that a correct and sensible way of doing that? It seems to work, but I am not sure it is the best way.If Application.CountIf(Rng.Offset(, -4), Dn.Offset(, -4)) > 1 Then '-4=B If Not .Exists(Dn.Value) Then .Add Dn.Value, Dn.Offset(, -4) '-4=B
Also, I realized that I need to run another check after cleaning the data. I need to compare values in F to see if a cell that contains another cell's data also has the same data of column O, and if they do I need to delete the row with the shortest value in F.
Example:
F O
Bart Bevers 12345
Bevers 12345
Would become:
F O
Bart Bevers 12345
I was looking at it and it seems like I could recycle the code from the original macro, but I am not sure how to best go about checking for if values in a cell in F are found in another cell in F.
Thanks, any help is appreciated.
Try this for the first :-
and this for the second:-Sub MG08Jul22 Dim Rng As Range, Dn As Range, n As Long Dim Twn As String Dim nRng As Range Set Rng = Range(Range("B1"), Range("B" & Rows.Count).End(xlUp)) With CreateObject("scripting.dictionary") .CompareMode = vbTextCompare For Each Dn In Rng Twn = Dn & Dn.Offset(, 4) If Not .Exists(Dn.Value) Then .Add Dn.Value, "" Else If nRng Is Nothing Then Set nRng = Dn Else Set nRng = Union(nRng, Dn) End If End If Next End With If Not nRng Is Nothing Then nRng.EntireRow.Delete End If End Sub
Regards MickSub MG08Jul25 Dim Rng As Range, Dn As Range, n As Long Dim nRng As Range Dim Q As Variant Dim K, T As Range Set Rng = Range(Range("O1"), Range("O" & Rows.Count).End(xlUp)) With CreateObject("scripting.dictionary") .CompareMode = vbTextCompare For Each Dn In Rng If Not .Exists(Dn.Value) Then n = n + 1 .Add Dn.Value, Array(Dn, Dn) Else Q = .Item(Dn.Value) If Len(Dn.Offset(, -9)) > Len(Q(0).Offset(, -9).Value) Then Set Q(0) = Dn End If If nRng Is Nothing Then Set Q(1) = Union(Q(1), Dn) End If .Item(Dn.Value) = Q End If Next For Each K In .keys If .Item(K)(1).Count > 1 Then For Each T In .Item(K)(1) If Not .Item(K)(0).Address = T.Address Then If nRng Is Nothing Then Set nRng = T Else Set nRng = Union(nRng, T) End If End If Next T End If Next K If Not nRng Is Nothing Then 'nRng.Interior.ColorIndex = 35 nRng.EntireRow.Delete End If End With End Sub
Thanks again MickG. Sorry for the slow reply, I was gone the last few days.
This is great, the code works exactly the way I wanted it to. I still have some way to go myself.
Again, you have been an incredible source of help. It is much appreciated.
Mod: this thread can be marked solved. Thanks.
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks