The code works when I bite off a couple hundred rows at a time, but always hangs somewhere in the middle when I try to run it on 10,000.
What the code does: Looks for duplicate entries in column A, adds the values in columns c, d and e between the two rows, then deletes the original row.
Can anybody think of a more stable way to do this, or point me towards why it might be locking up?
Sub combineDelete ()
Const TEST_COLUMN As String = "A"
Dim i As Long
Dim iLastRow As Long
With ActiveSheet
iLastRow = .Cells(.Rows.Count, TEST_COLUMN).End(xlUp).Row
For i = iLastRow To 2 Step -1
If Cells(i, 1) = Cells(i - 1, 1) Then
s = Cells(i, 3).Value
t = Cells(i - 1, 3).Value
Cells(i - 1, 3) = s + t
u = Cells(i, 4).Value
v = Cells(i - 1, 4).Value
Cells(i - 1, 4) = u + v
w = Cells(i, 5).Value
y = Cells(i - 1, 5).Value
Cells(i - 1, 5) = w + y
Cells(i, 1).EntireRow.Delete
End If
Next i
End With
End Sub
Edit: Here's a link to a sample subset of the data.
Post-edit: Every one of these ideas is effective. Ron Rosenberg's solution below manages to handle it orders of magnitude faster than any solution I tinkered with. Thanks!
Working with ~10K rows would benefit immensely from a variant array but you can also make significant improvements by deleting all of the rows at once. While you could gather a Union of the rows to delete, a Range.RemoveDuplicates method is also appropriate in this case.
It is unclear on whether your data is sorted on a primary key of column A. Your current code depends upon this but I've changed the criteria check to the Excel Application object's MATCH function to accommodate unsorted data.
Your code appears to avoid text column header labels in row 1. I've used the Range.CurrentRegion property to localize the cells to be processed.
The use of
Application.Sum(..., ...)
is a trifle slower than straight addition but it has the benefit of providing error control over text values. This may or may not be a desired behavior; i.e. you might want to know when you are trying to add text to a number instead of skipping over it.There were many places inside your With ... End With statement where you used
Cells(i, 3)
and not.Cells(i, 3)
(note the prefix.
). If you are going to take the time to reference the Range.Parent property (and you should always do so!) then it seems a shame not to use it.I've included a reusable 'helper' sub that 'turns off' many application environment states but left it commented. Uncomment it once you havew completed debugging for additional speed and stability.
Addendum for lookup strings with length > 255
A dictionary object provides lightning fast lookups due to its unique keys. Since these are a variant type, there is no 255 character limit.
Start with this and let us know how things are going afterwards:
Notes:
.Value2
instead of.Value
ActiveSheet
added by adding dots.
Here is a routine that should run quite rapidly. You will note near the top of the code where to change the source and results worksheets if you want.
The work is done within VBA arrays, which will be much faster than working on the worksheet.
I create a User defined object whose properties are the contents of the TestColumn; the Maximum amount in Column B; and an array of the Sum of Columns C, D and E.
These are placed into a Collection object with the Key being the TestColumn. If there is a duplicate, the Collection object will return a 457 error, which we test for and use to combine the rows.
Finally, we write the collection object back to an array, and write that array to the worksheet.
You will use both a Class Module and a Regular Module
The original data does not need to be sorted, but you can if you want, either before or after running this macro.
Enjoy.
Class Module
Be sure to rename this module cCombo after inserting it
Regular Module