I have basic understanding of VBA, so any help is appreciated. I want to count unique columns a, b, e, and remove the duplicates. columns c, d are to be summarized. The code I have now only works on the first 3 columns (code attached and before and after current macro via images). I am not sure how to add in the additional requirements. Thank you
Before Macro
After Current Macro
Sub LineSmasher()
Dim dict As Object, i As Long, dKey As String
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
dKey = (Cells(i, 1) & " " & Cells(i, 2))
dict(dKey) = Cells(i, 3) + dict(dKey)
Next i
Range(Range("A1"), Range("C" & Rows.Count).End(xlUp)).RemoveDuplicates Columns:=Array(1, 2)
For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
dKey = (Cells(i, 1) & " " & Cells(i, 2))
If Not Cells(i, 3) = dict(dKey) Then Cells(i, 3) = dict(dKey)
Next i
End Sub
Scan up the sheet, use the dictionary to reference the row where key first occurred. Summate the values and delete row.
Option Explicit
Sub LineSmasher()
Dim dict As Object, sKey As String
Dim ws As Worksheet, rngDel As Range
Dim i As Long, r As Long, n As Long, lastrow As Long
Set dict = CreateObject("Scripting.Dictionary")
Set ws = ThisWorkbook.Sheets("Sheet1")
With ws
lastrow = .Range("A" & .Rows.Count).End(xlUp).Row
For i = lastrow To 2 Step -1
sKey = .Cells(i, 1) & " " & .Cells(i, 2)
If dict.exists(sKey) Then
r = dict(sKey)
' summate
.Cells(r, "C") = .Cells(r, "C") + .Cells(i, "C")
' delete later
If rngDel Is Nothing Then
Set rngDel = .Rows(i)
Else
Set rngDel = Union(rngDel, .Rows(i))
End If
n = n + 1
Else
dict.Add sKey, i
End If
Next
End With
If rngDel Is Nothing Then
MsgBox "No lines deleted", vbExclamation
Else
rngDel.Interior.Color = vbRed
If MsgBox("Delete rows", vbYesNo) = vbYes Then
rngDel.Delete
MsgBox n & " lines deleted", vbInformation
End If
End If
End Sub
Related
I have the workbook below that shows clock in and out each day for each employee and shop. I was able to find the cell and if they are late after 8:00 am then it will debug.print that the employee was late. The problem I have now is that sometimes the employee goes on a lunch break and its reading the second time clocked in as if he was late. I would like to print notes on the sheet that will tell me for example "Nathan was late on Monday, 8:47:43 AM" and if he left during the day and came back. For example "Trent left Monday on 12:54 PM and came back on 1:28 PM". I am just having trouble reading through multiple times on the same day. The below code is what I have so far. Any ideas?
Sheet :
Sub TestFindAll()
Dim SearchRange As Range
Dim FindWhat As Variant
Dim FoundCells As Range
Dim FoundCell As Range
Dim LastRowA As Long, LastRowJ As Long
Dim WS1 As Worksheet
Set WS1 = ThisWorkbook.Worksheets("DailyTimeSheet")
LastRowJ = WS1.Range("J" & WS1.Rows.Count).End(xlUp).Row
Debug.Print LastRowJ
Dim firstAddress As String
With WS1
Dim tbl As ListObject: Set tbl = .Range("DailyTime").ListObject
Set SearchRange = tbl.ListColumns("EmployeeName").Range
End With
For t = 2 To LastRowJ
FindWhat = WS1.Range("J" & t)
Set FoundCells = SearchRange.Find(What:=FindWhat, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows)
If Not FoundCells Is Nothing Then
firstAddress = FoundCells.Address
Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2).Value
Do
If Not FoundCells.Offset(0, 2).Value = "Sat" And FoundCells.Offset(0, 5).Value < TimeValue("18:00:00") Then
Debug.Print FoundCells.Value & " left early on " & FoundCells.Offset(0, 2) & " at " & TimeValue(Format(FoundCells.Offset(0, 5).Value, "hh:mm:ss"))
End If
Set FoundCells = SearchRange.FindNext(FoundCells)
' Debug.Print "Found " & FoundCells.Value & " " & FoundCells.Offset(0, 2)
Loop While Not FoundCells Is Nothing And FoundCells.Address <> firstAddress
End If
Next
End Sub
Use a Dictionary Object with names as key to identify the first in or last out time of the day.
Option Explicit
Sub macro()
Dim lastrow As Long, r As Long, dt As String
Dim dict As Object, key, n As Long, c As Range
Set dict = CreateObject("Scripting.Dictionary")
With Sheet1 'ThisWorkbook.Worksheets("DailyTimeSheet")
.Cells.Interior.Pattern = xlNone
lastrow = .Cells(.Rows.Count, "J").End(xlUp).Row
' check in times
For Each c In .Range("J2:J" & lastrow).Cells
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
' is this first for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
c.Offset(, 4) > TimeValue("08:00:00") Then
c.Offset(, 4).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
' reverse scan to check out times
dict.RemoveAll
For r = lastrow To 2 Step -1
Set c = .Cells(r, "J")
dt = Format(c.Offset(, 2), "yyyy-mm-dd")
key = Trim(c.Value)
' initialise
If Not dict.exists(key) Then
dict.Add key, "0000-00-00"
End If
'is the last for the day
If dict(key) <> dt Then
If c.Offset(, 2).Value <> "Sat" And _
(c.Offset(, 5) < TimeValue("18:00:00")) Then
c.Offset(, 5).Interior.Color = RGB(255, 255, 0)
n = n + 1
End If
End If
dict(key) = dt ' store
Next
MsgBox n & " cells highlighted", vbInformation
End With
End Sub
I got data in sheet1 and sheet2, which i want to copy and paste in sheet3. That is already done. So next i want to match rows, by checking column C, D, E, H and I. The C and H column value is integer and the rest is text/strings.
If two rows match, then i want to copy and paste one of the lines in a new third sheet, and add the integer difference from column H in column H (The difference will be 0 if the lines match in all columns)
If the two rows dont match, copy and paste one of the lines in a new fourth sheet, and add the integer difference from column H in column H
The code so far:
Sub CopyPasteSheet()
Dim mySheet, arr
arr = Array("Sheet1", "Sheet2")
Const targetSheet = "Sheet3"
Application.ScreenUpdating = False
For Each mySheet In arr
Sheets(mySheet).Range("A1").CurrentRegion.Copy
With Sheets(targetSheet)
.Range("A1").Insert Shift:=xlDown
If mySheet <> arr(UBound(arr)) Then .Rows(1).Delete xlUp
End With
Next mySheet
Application.ScreenUpdating = True
End Sub
Code so far, but i receive a code error "Application-defined or object-defined error". It does copy the rows which match into a new sheet and state the difference as 0 in column H, but it doesn't work for the ones that dont match.
Sub MatchRows()
Dim a As Variant, b As Variant, c As Variant, d As Variant
Dim i As Long, j As Long, k As Long, m As Long, n As Long
Dim dic As Object, ky As String
Set dic = CreateObject("Scripting.Dictionary")
a = Sheets("Sheet1").Range("A1:I" & Sheets("Sheet1").Range("H" & Rows.Count).End(3).Row).Value
b = Sheets("Sheet2").Range("A1:I" & Sheets("Sheet2").Range("H" & Rows.Count).End(3).Row).Value
ReDim c(1 To UBound(a, 1), 1 To UBound(a, 2))
ReDim d(1 To UBound(a, 1), 1 To UBound(a, 2))
For i = 1 To UBound(b, 1)
ky = b(i, 3) & "|" & b(i, 4) & "|" & b(i, 5) & "|" & b(i, 9)
dic(ky) = i
Next
For i = 2 To UBound(a, 1)
ky = a(i, 3) & "|" & a(i, 4) & "|" & a(i, 5) & "|" & a(i, 9)
If dic.exists(ky) Then
j = dic(ky)
If a(i, 8) = b(j, 8) Then
k = k + 1
For n = 1 To UBound(a, 2)
c(k, n) = a(i, n)
Next
c(k, 8) = 0
Else
m = m + 1
For n = 1 To UBound(a, 2)
d(k, n) = a(i, n)
Next
d(k, 8) = a(i, 8) - b(j, 8)
End If
End If
Next
Sheets("Sheet3").Range("A" & Rows.Count).End(3)(2).Resize(k, UBound(a, 2)).Value = c
Sheets("Sheet4").Range("A" & Rows.Count).End(3)(2).Resize(m, UBound(a, 2)).Value = d
End Sub
Unless the performance is too slow remove the complexity of arrays by writing to the output sheets one line at a time.
Update - copy complete line
Option Explicit
Sub MatchRows2()
Dim dic As Object, key As String
Set dic = CreateObject("Scripting.Dictionary")
Dim wb As Workbook
Dim ws As Worksheet, ws3 As Worksheet, ws4 As Worksheet
Dim iLastRow As Long, s As String, diff As Long
Dim iRow3 As Long, iRow4 As Long, i As Long, t0 As Single
Dim rng As Range
t0 = Timer
s = "|"
Set wb = ThisWorkbook
' sheet 2
Set ws = wb.Sheets("Sheet2")
iLastRow = ws.Cells(Rows.Count, "H").End(xlUp).Row
For i = 2 To iLastRow
key = ws.Cells(i, "C") & s & ws.Cells(i, "D") _
& s & ws.Cells(i, "E") & s & ws.Cells(i, "I")
If dic.exists(key) Then
MsgBox "Duplicate key '" & key & "'", vbCritical, "Sheet2 Row " & i
Exit Sub
Else
dic.Add key, ws.Cells(i, "H")
End If
Next
Debug.Print dic.Count
' results
Set ws3 = wb.Sheets("Sheet3")
iRow3 = ws3.Cells(Rows.Count, "A").End(xlUp).Row
Set ws4 = wb.Sheets("Sheet4")
iRow4 = ws4.Cells(Rows.Count, "A").End(xlUp).Row
'sheet 1
Application.ScreenUpdating = False
Set ws = wb.Sheets("Sheet1")
iLastRow = ws.Cells(Rows.Count, "H").End(xlUp).Row
For i = 2 To iLastRow
key = ws.Cells(i, "C") & s & ws.Cells(i, "D") _
& s & ws.Cells(i, "E") & s & ws.Cells(i, "I")
If dic.exists(key) Then
diff = ws.Cells(i, "H") - dic(key)
If diff = 0 Then
iRow3 = iRow3 + 1
Set rng = ws3.Cells(iRow3, "A")
Else
iRow4 = iRow4 + 1
Set rng = ws4.Cells(iRow4, "A")
End If
ws.Rows(i).Copy rng
rng.Offset(0, 7).Value = diff ' col H
End If
Next
Application.ScreenUpdating = True
MsgBox "Done in " & Format(Timer - t0, "0.0 secs"), vbInformation
End Sub
I am trying to sum values in column "I" and delete duplicate rows if value in column "E" is the same and value in column "G" is "Kede".
I have this piece of code that I don't fully understand that I'm trying to modify for my needs. Originally this code was looking for duplicate values in column "E" and summing values in column "I" deleting the duplicate rows.
'Declare variables
Dim AcSh As Worksheet, LastRow As Long, dict As Object
Dim rngDel As Range, arrE, arrInt, arrI, i As Long, dKey
Set AcSh = ActiveSheet
LastRow = AcSh.Range("E" & AcSh.Rows.Count).End(xlUp).Row
arrE = AcSh.Range("E2:E" & LastRow).Value
Set dict = CreateObject("Scripting.Dictionary")
'Sum and delete duplicates
On Error Resume Next
For i = 1 To UBound(arrE)
If Not dict.Exists(arrE(i, 1)) Then
dict.Add arrE(i, 1), AcSh.Range("I" & i + 1).Address & "|" & CDbl(AcSh.Range("I" & i + 1).Value)
Else
arrInt = Split(dict(arrE(i, 1)), "|")
dict(arrE(i, 1)) = arrInt(0) & "|" & CDbl(arrInt(1)) + CDbl(AcSh.Range("I" & i + 1).Value)
If rngDel Is Nothing Then
Set rngDel = AcSh.Range("E" & i + 1)
Else
Set rngDel = Union(rngDel, AcSh.Range("E" & i + 1))
End If
End If
Next i
On Error Resume Next
ReDim arrI(1 To LastRow, 1 To 1)
For Each dKey In dict.keys()
arrInt = Split(dict.Item(dKey), "|")
arrI(Range(arrInt(0)).Row - 1, 1) = CDbl(arrInt(1))
Next
If Not rngDel Is Nothing Then
AcSh.Range("I2").Resize(LastRow - 1, 1).Value = arrI
rngDel.EntireRow.Delete
End If
And this is what I have so far
'Declare variables
Dim AcSh As Worksheet, LastRow As Long, dict As Object
Dim rngDel As Range, arrG, arrInt, arrI, i As Long, dKey
Set AcSh = ActiveSheet
LastRow = AcSh.Range("G" & AcSh.Rows.Count).End(xlUp).Row
arrG = AcSh.Range("G2:G" & LastRow).Value
Set dict = CreateObject("Scripting.Dictionary")
'Sum and delete duplicates
On Error Resume Next
For i = 1 To UBound(arrG)
If Not dict.Exists(arrG(i, 1)) And ThisWorkbook.Worksheets("BOM").Range(i, G).Value = "Kede" Then
dict.Add arrG(i, 1), AcSh.Range("I" & i + 1).Address & "|" & CDbl(AcSh.Range("I" & i + 1).Value)
Else:
arrInt = Split(dict(arrG(i, 1)), "|")
dict(arrG(i, 1)) = arrInt(0) & "|" & CDbl(arrInt(1)) + CDbl(AcSh.Range("I" & i + 1).Value)
If rngDel Is Nothing Then
Set rngDel = AcSh.Range("G" & i + 1)
Else:
Set rngDel = Union(rngDel, AcSh.Range("G" & i + 1))
End If
End If
Next i
On Error Resume Next
ReDim arrI(1 To LastRow, 1 To 1)
For Each dKey In dict.keys()
arrInt = Split(dict.Item(dKey), "|")
arrI(Range(arrInt(0)).Row - 1, 1) = CDbl(arrInt(1))
Next
If Not rngDel Is Nothing Then
AcSh.Range("I2").Resize(LastRow - 1, 1).Value = arrI
rngDel.EntireRow.Delete
End If
So basically I am trying to add one more criteria to original code that would also look for if the value in column "G" is "Kede".
Could someone, please, help me modify this code and explain it more clearly to me?
If I understand correctly, you would like to ignore and remove and rows without "Kede" in column G. If so, this code should do the trick by removing them at the beginning.
'Declare variables
Dim AcSh As Worksheet, LastRow As Long, dict As Object
Dim rngDel As Range, arrE, arrInt, arrI, i As Long, dKey
Set AcSh = ActiveSheet
LastRow = AcSh.Range("E" & AcSh.Rows.Count).End(xlUp).Row
'Remove non-Kede rows and reset LastRow
For i = LastRow + 1 To 2 Step -1
If AcSh.Range("G" & i).Value <> "Kede" Then AcSh.Range("G" & i).EntireRow.Delete
Next i
LastRow = AcSh.Range("E" & AcSh.Rows.Count).End(xlUp).Row
arrE = AcSh.Range("E2:E" & LastRow).Value
Set dict = CreateObject("Scripting.Dictionary")
'Sum and delete duplicates
On Error Resume Next
For i = 1 To UBound(arrE)
If Not dict.Exists(arrE(i, 1)) Then
dict.Add arrE(i, 1), AcSh.Range("I" & i + 1).Address & "|" & CDbl(AcSh.Range("I" & i + 1).Value)
Else
arrInt = Split(dict(arrE(i, 1)), "|")
dict(arrE(i, 1)) = arrInt(0) & "|" & CDbl(arrInt(1)) + CDbl(AcSh.Range("I" & i + 1).Value)
If rngDel Is Nothing Then
Set rngDel = AcSh.Range("E" & i + 1)
Else
Set rngDel = Union(rngDel, AcSh.Range("E" & i + 1))
End If
End If
Next i
On Error Resume Next
ReDim arrI(1 To LastRow, 1 To 1)
For Each dKey In dict.keys()
arrInt = Split(dict.Item(dKey), "|")
arrI(Range(arrInt(0)).Row - 1, 1) = CDbl(arrInt(1))
Next
If Not rngDel Is Nothing Then
AcSh.Range("I2").Resize(LastRow - 1, 1).Value = arrI
rngDel.EntireRow.Delete
End If
Edit: Thanks to the comments below, I believe I understand now what you are hoping for. I'm pretty sure this isn't the most eloquent way to solve the problem but I think it works. Please try.
'Declare variables
Dim AcSh As Worksheet, LastRow As Long, dict As Object
Dim rngDel As Range, arrE, arrInt, arrI, i As Long, dKey
Set AcSh = ActiveSheet
LastRow = AcSh.Range("E" & AcSh.Rows.Count).End(xlUp).Row
'Remove non-Kede rows and reset LastRow
' For i = LastRow + 1 To 2 Step -1
' If AcSh.Range("G" & i).Value <> "Kede" Then AcSh.Range("G" & i).EntireRow.Delete
' Next i
LastRow = AcSh.Range("E" & AcSh.Rows.Count).End(xlUp).Row
arrE = AcSh.Range("E2:E" & LastRow).Value
arrG = AcSh.Range("G2:G" & LastRow).Value
Set dict = CreateObject("Scripting.Dictionary")
'Sum and delete duplicates
On Error Resume Next
For i = 1 To UBound(arrE)
If Not dict.Exists(arrE(i, 1) & arrG(i, 1)) Then
dict.Add arrE(i, 1) & arrG(i, 1), AcSh.Range("I" & i + 1).Address & "|" & CDbl(AcSh.Range("I" & i + 1).Value)
ElseIf arrG(i, 1) = "Kede" Then
arrInt = Split(dict(arrE(i, 1) & arrG(i, 1)), "|")
dict(arrE(i, 1) & arrG(i, 1)) = arrInt(0) & "|" & CDbl(arrInt(1)) + CDbl(AcSh.Range("I" & i + 1).Value)
If rngDel Is Nothing Then
Set rngDel = AcSh.Range("E" & i + 1)
Else
Set rngDel = Union(rngDel, AcSh.Range("E" & i + 1))
End If
Else
dict.Add AcSh.Range("E" & i + 1).Address, AcSh.Range("I" & i + 1).Address & "|" & CDbl(AcSh.Range("I" & i + 1).Value)
End If
Next i
On Error Resume Next
ReDim arrI(1 To LastRow, 1 To 1)
For Each dKey In dict.keys()
arrInt = Split(dict.Item(dKey), "|")
arrI(Range(arrInt(0)).Row - 1, 1) = CDbl(arrInt(1))
Next
If Not rngDel Is Nothing Then
AcSh.Range("I2").Resize(LastRow - 1, 1).Value = arrI
rngDel.EntireRow.Delete
End If
This code is definitely a bit confusing. Essentially, they are making a dictionary with keys from E:E and values from I:I. It may be possible to rework this but may I suggest an easier alternative: pivot tables. They are much more flexible and less likely to break. I put together a mock sheet to show you want it would look like:
To make this yourself to the following:
Select the columns with data (E:I)
Click Insert -> Pivot Table
Drag the header names for columns E:E, G:G, and I:I to where Column1, Column2, and Column3, are in the picture.
Change the filter the Kede
I hope this helps! If you have questions, I'll try my best to help.
Assume I have data in column (A) like the following:
Names
Yasser
Hany
Ahmed
Reda
Ahmed
Yasser
Reda
Yasser
Duplicates can be detected using such a code
Sub Find_Duplicates()
Dim e, x(), dic As Object, cel As Range, lr As Long, i As Long
Application.ScreenUpdating = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
For Each cel In Range("A1:A" & lr)
If Not .Exists(cel.Value) Then
.Item(cel.Value) = cel.Value & "^" & cel.Address(0, 0)
Else
.Item(cel.Value) = Split(.Item(cel.Value), "^")(0) & " | " & cel.Value & "^" & Split(.Item(cel.Value), "^")(1) & " | " & cel.Address(0, 0)
End If
Next cel
If .Count Then
ReDim x(1 To .Count, 1 To 2)
For Each e In .Keys
If InStr(.Item(e), "|") > 0 Then
i = i + 1
x(i, 1) = Split(.Item(e), "^")(0)
x(i, 2) = Split(.Item(e), "^")(1)
End If
Next e
End If
Columns("F:G").ClearContents
Range("F1:G1").Value = Array("Duplicate Entries", "Address")
If i > 0 Then Range("F2").Resize(i, 2).Value = x
End With
Application.ScreenUpdating = True
End Sub
The output would be in columns F & G like that
What I am trying to get is like that (in Column B)
If you decide on formulas instead, then you could use:
Formula in B2:
=IF(COUNTIF(A$2:A$9,A2)>1,"Duplicate"&MATCH(A2,UNIQUE(FILTER(A$2:A$9,COUNTIF(A$2:A$9,A$2:A$9)>1)),0),"")
Non-ExcelO365 users could use:
=IF(COUNTIF(A$2:A$9,A2)>1,IF(MATCH(A2,A$1:A$9,0)=ROW(),"Duplicate"&MAX(IFERROR(--MID(B$1:B1,10,99),0))+1,INDEX(B$1:B1,MATCH(A2,A$1:A$9,0))),"")
Be sure to accept the formula through CtrlShiftEnter
You could modify your subroutine like this:
Sub Find_Duplicates()
Dim e, x(), dic As Object, cel As Range, lr As Long, i As Long, j As Long, arr() As String
Application.ScreenUpdating = False
lr = Cells(Rows.Count, 1).End(xlUp).Row
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
For Each cel In Range("A1:A" & lr)
If Not .Exists(cel.Value) Then
.Item(cel.Value) = cel.Value & "^" & cel.Address(0, 0)
Else
.Item(cel.Value) = Split(.Item(cel.Value), "^")(0) & " | " & cel.Value & "^" & Split(.Item(cel.Value), "^")(1) & " | " & cel.Address(0, 0)
End If
Next cel
If .Count Then
ReDim x(1 To .Count, 1 To 2)
For Each e In .Keys
If InStr(.Item(e), "|") > 0 Then
i = i + 1
arr = Split(Split(.Item(e), "^")(1), "|")
For j = LBound(arr) To UBound(arr)
Set cel = Range(Trim(arr(j)))
Cells(cel.Row, cel.Column + 1).Value = "Duplicate" & CStr(i)
Next j
End If
Next e
End If
End With
Application.ScreenUpdating = True
End Sub
Here, the cell addresses are split from each item and into an array of strings. Each cell address is used to move one cell to the right and then write the duplicate number there.
I am trying to eliminate line items that cancel each other out.
For example, below the two rows that add to zero would be deleted (i.e., 87.1 and -87.1).
-87.1
890
87.1
898989
The code that I am using mostly works but in cases where there are numerous lines with the same values it is deleting all of them instead of just one matching value per observation. For example, below, I would want it to cancel out two of the -87.1s and two of the 87.1s but one would be leftover because there is no number directly offsetting it.
-87.1
890
87.1
898989
87.1
-87.1
-87.1
Sub x()
Dim n As Long, rData As Range
Application.ScreenUpdating = False
n = Range("C" & Rows.Count).End(xlUp).Row
Range("AV2:AV" & n).Formula = "=IF(I2=0,0,COUNTIFS($C$2:$C$" & n & ",C2,$I$2:$I$" & n & ",-I2))"
With ActiveSheet
.AutoFilterMode = False
.Rows(1).AutoFilter field:=48, Criteria1:=">0"
With .AutoFilter.Range
On Error Resume Next
Set rData = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not rData Is Nothing Then
rData.EntireRow.Delete shift:=xlUp
End If
End With
.AutoFilterMode = False
End With
Application.ScreenUpdating = True
End Sub
I think you need something like this:
Sub DeleteOppositeNumbers()
Dim Fnd As Range, r As Long
'By: Abdallah Ali El-Yaddak
Application.ScreenUpdating = False
'Loop through the column bottom to top.
For r = Range("C" & Rows.Count).End(xlUp).Row To 2 Step -1
If Cells(r, 3).Value > 0 Then 'If the value is positive
'Sreach for it's opposite
Set Fnd = Columns(3).Find(-Cells(r, 3).Value, LookAt:=xlWhole)
'If found, delete both.
If Not Fnd Is Nothing Then Rows(r).Delete: Fnd.EntireRow.Delete
End If
Next
'Just to restore normal behaviour of sreach
Set Fnd = Columns(3).Find(Cells(3, 2).Value, LookAt:=xlPart)
Application.ScreenUpdating = True
End Sub
Perhaps Something Simpler:
Sub x()
Dim ar() As Variant
Dim i As Integer
Dim j As Integer
Dim n As Integer
n = Range("C" & Rows.Count).End(xlUp).Row
Range("AV2:AV" & n).Formula = "=IF(I2=0,0,COUNTIFS($C$2:$C$" & n & ",C2,$I$2:$I$" & n & ",-I2))"
ar = ActiveSheet.Range("AV2:AV" & last).Value
For i = LBound(ar) To UBound(ar)
For j = LBound(ar) To UBound(ar)
If i <> j Then
If ar(i, 1) = ar(j, 1) Then
ar(i, 1) = ""
ar(j, 1) = ""
End If
End If
Next
Next
For i = LBound(ar) To UBound(ar)
ActiveSheet.Range("AV" & i + 1).Value = ar(i, 1)
Next
ActiveSheet.Range("AV2:AV" & last).SpecialCells(xlCellTypeBlanks).Delete xlUp
End Sub
I have tried and tested this one.
You could try:
Option Explicit
Sub test()
Dim arr As Variant
Dim LastRow As Long, i As Long, j As Long
With ThisWorkbook.Worksheets("Sheet1")
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
arr = Range("A1:A" & LastRow)
For i = UBound(arr) To LBound(arr) Step -1
For j = UBound(arr) - 1 To LBound(arr) Step -1
If arr(i, 1) + arr(j, 1) = 0 Then
.Rows(i).EntireRow.Delete
.Rows(j).EntireRow.Delete
Exit For
End If
Next j
Next i
End With
End Sub