I'm trying to create a macro which copies rows of data after comparing a column value. I previously asked this question but made some progress, and thought it would be less confusing if i posted another question. The column to be compared is "eRequest ID" and it consists of integers and text.
I have two worksheets, both with "eRequest ID" as the first column. The goal here is to copy ANY rows of data that has an "eRequest ID" NOT FOUND in both worksheets. Meaning if this record's "eRequest ID" is only found on one worksheet and not both, the whole row of data has to be copied into a third new worksheet.
I have worked out some codes after browsing through the net, and with the help of the coding experts here. The problem with this codes is that somehow I get a "mismatch" for every row. I tried changing the foundTrue value here and there but it doesn't seem to work. I need it to only copy rows of data with only 1 "eRequest ID" on either worksheet. Greatful for any help and appreciate your effort!
Sub compareAndCopy()
Dim lastRowE As Integer
Dim lastRowF As Integer
Dim lastRowM As Integer
Dim foundTrue As Boolean
Application.ScreenUpdating = False
lastRowE = Sheets("JULY15Release_Master Inventory").Cells(Sheets("JULY15Release_Master Inventory").Rows.Count, "A").End(xlUp).Row
lastRowF = Sheets("JULY15Release_Dev status").Cells(Sheets("JULY15Release_Dev status").Rows.Count, "A").End(xlUp).Row
lastRowM = Sheets("Mismatch").Cells(Sheets("Mismatch").Rows.Count, "A").End(xlUp).Row
For i = 1 To lastRowE
foundTrue = True
For j = 1 To lastRowF
'If Sheets("JULY15Release_Master Inventory").Cells(i, 2).Value = Sheets("JULY15Release_Dev status").Cells(j, 7).Value Then
If Sheets("JULY15Release_Master Inventory").Cells(i, 2).Value <> Sheets("JULY15Release_Dev status").Cells(j, 7).Value Then
foundTrue = False
Exit For
End If
Next j
If foundTrue Then
Sheets("JULY15Release_Dev status").Rows(i).Copy Destination:= _
Sheets("Mismatch").Rows(lastRowM + 1)
lastRowM = lastRowM + 1
End If
Next i
Application.ScreenUpdating = False
End Sub
another one variant
Sub test()
Dim lastRowE&, lastRowF&, lastRowM&, Key As Variant
Dim Cle As Range, Clf As Range
Dim DicInv As Object: Set DicInv = CreateObject("Scripting.Dictionary")
Dim DicDev As Object: Set DicDev = CreateObject("Scripting.Dictionary")
Application.ScreenUpdating = 0
lastRowE = Sheets("JULY15Release_Master Inventory").Cells(Rows.Count, "A").End(xlUp).Row
lastRowF = Sheets("JULY15Release_Dev status").Cells(Rows.Count, "A").End(xlUp).Row
lastRowM = Sheets("Mismatch").Cells(Rows.Count, "A").End(xlUp).Row
'add into dictionary row number from Inventory where cell is matched
For Each Cle In Sheets("JULY15Release_Master Inventory").Range("A1:A" & lastRowE)
If Cle.Value <> "" Then
For Each Clf In Sheets("JULY15Release_Dev status").Range("A1:A" & lastRowF)
If UCase(Cle.Value) = UCase(Clf.Value) Then DicInv.Add Cle.Row, ""
Next Clf
End If
Next Cle
'add into dictionary row number from Dev where cell is matched
For Each Clf In Sheets("JULY15Release_Dev status").Range("A1:A" & lastRowF)
If Clf.Value <> "" Then
For Each Cle In Sheets("JULY15Release_Master Inventory").Range("A1:A" & lastRowE)
If UCase(Clf.Value) = UCase(Cle.Value) Then DicDev.Add Clf.Row, ""
Next Cle
End If
Next Clf
'Get mismatch from Inventory
With Sheets("JULY15Release_Master Inventory")
For Each Cle In .Range("A1:A" & lastRowE)
If Not DicInv.exists(Cle.Row) And Cle.Value <> "" Then
.Rows(Cle.Row).Copy Sheets("Mismatch").Rows(lastRowM)
lastRowM = lastRowM + 1
End If
Next Cle
End With
'Get mismatch from Dev
With Sheets("JULY15Release_Dev status")
For Each Clf In .Range("A1:A" & lastRowF)
If Not DicDev.exists(Clf.Row) And Clf.Value <> "" Then
.Rows(Clf.Row).Copy Sheets("Mismatch").Rows(lastRowM)
lastRowM = lastRowM + 1
End If
Next Clf
End With
Application.ScreenUpdating = 1
End Sub
Sample
JULY15Release_Master Inventory
JULY15Release_Dev status
Output Result
Mismatch
Try this, it should work, TESTED.
Sub test()
Dim lrow1 As Long
Dim lrow2 As Long
Dim i As Long
Dim K As Long
Dim j As Long
Dim p As Variant
Dim wb As Workbook
Set wb = ThisWorkbook
K = 2
lrow1 = wb.Sheets("JULY15Release_Master Inventory").Range("A" & Rows.Count).End(xlUp).Row
lrow2 = wb.Sheets("JULY15Release_Dev status").Range("A" & Rows.Count).End(xlUp).Row
For i = 1 To lrow1
p = Application.Match(wb.Sheets("JULY15Release_Master Inventory").Range("A" & i).Value, wb.Sheets("JULY15Release_Dev status").Range("A1" & ":" & "A" & lrow2), 0)
If IsError(p) Then
wb.Sheets("JULY15Release_Master Inventory").Rows(i).Copy Destination:=Sheets("Mismatch").Rows(K)
K = K + 1
End If
Next
For j = 1 To lrow2
p = Application.Match(wb.Sheets("JULY15Release_Dev status").Range("A" & j).Value, wb.Sheets("JULY15Release_Master Inventory").Range("A1" & ":" & "A" & lrow1), 0)
If IsError(p) Then
wb.Sheets("JULY15Release_Dev status").Rows(j).Copy Destination:=Sheets("Mismatch").Rows(K)
K = K + 1
End If
Next
End Sub
Related
i tried using dictionary but it only counts the repetition but i want to know the exact frequency of all datas in a column
what ive used is
Sub countThings()
Dim ws As Worksheet
Dim lastrow As Long, x As Long
Dim items As Object
Application.ScreenUpdating = False
Set ws = ActiveSheet
lastrow = ws.Range("B" & Rows.count).End(xlUp).Row
Set items = CreateObject("Scripting.Dictionary")
For x = 2 To lastrow
If Not items.exists(ws.Range("B" & x).Value) Then
items.Add ws.Range("B" & x).Value, 1
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
Else
items(ws.Range("B" & x).Value) = items(ws.Range("B" & x).Value) + 1
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
End If
Next x
items.RemoveAll
End Sub
and this gives me
[1: https://i.stack.imgur.com/Mhp5g.png][1]
but what i need is
[4: https://i.stack.imgur.com/UYOFu.png][4]
I think this is what you were after. Please try it.
Sub CountThings()
Dim Ws As Worksheet
Dim Items As Object ' Scripting.Dictionary
Dim Arr As Variant ' values in column B
Dim R As Long ' loop couner: Rows
Dim Key As Variant ' loop counter: dictionary keys
Set Items = CreateObject("Scripting.Dictionary")
Set Ws = ActiveSheet ' better: define tab by name
With Ws
' reading from the sheet is slow
' therefore read all items at once
Arr = .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp)).Value
' this is a 1-based 2-D array, like Arr([Rows], [Column])
' where column is always 1 because there's only 1 column
End With
For R = 1 To UBound(Arr)
If Items.Exists(Trim(Arr(R, 1))) Then
Items(Trim(Arr(R, 1))) = Items(Trim(Arr(R, 1))) + 1
Else
Items.Add Trim(Arr(R, 1)), 1
End If
Next R
ReDim Arr(1 To Items.Count, 1 To 2)
R = 0
For Each Key In Items.keys
R = R + 1
Arr(R, 1) = Key
Arr(R, 2) = Items(Key)
Next Key
' specify the top left cell of the target range
Ws.Cells(2, "C").Resize(UBound(Arr, 1), UBound(Arr, 2)).Value = Arr
Set Items = Nothing
End Sub
You need not Trim the Keys if you are sure that there can't be any stray leading or trailing blanks.
Your second picture doesn't need VBA. It can be produce by this formula, entered in C2 and copied down.
=COUNTIF($B$2:$B$13,$B2)
In fact, you can even do the job of my above code without VBA. Enter this formula in G2 of your sheet as an array formula (confirmed with CTL + SHIFT + ENTER if you don't have Excel 365), and the other one in H. Then copy both formulas down.
[G2] =IFERROR(INDEX($B$2:$B$13, MATCH(0, COUNTIF($G$1:G1, $B$2:$B$13), 0)), "")
[H2] =IF($G2<>"",COUNTIF($B$2:$B$13,$G2),"")
You need to assign values to column C after you have finished counting and therefore, need another loop:
Sub countThings()
Dim ws As Worksheet
Dim lastrow As Long, x As Long
Dim items As Object
Application.ScreenUpdating = False
Set ws = ActiveSheet
lastrow = ws.Range("B" & Rows.Count).End(xlUp).Row
Set items = CreateObject("Scripting.Dictionary")
For x = 2 To lastrow
If Not items.exists(ws.Range("B" & x).Value) Then
items.Add ws.Range("B" & x).Value, 1
Else
items(ws.Range("B" & x).Value) = items(ws.Range("B" & x).Value) + 1
End If
Next x
For x = 2 To lastrow
ws.Range("C" & x).Value = items(ws.Range("B" & x).Value)
Next x
items.RemoveAll
Set items = Nothing
End Sub
A simpler way to achieve what you want is to let excel do the counting for you like this:
Sub countThings2()
Dim sDataAddress As String
With ActiveSheet
sDataAddress = "$B$2:$B$" & .Cells(Rows.Count, "B").End(xlUp).Row
With .Range(sDataAddress).Offset(0, 1)
.Formula2 = "=COUNTIF(" & sDataAddress & ",B2)"
.Value = .Value
End With
End With
End Sub
i use table and 2 functions. not simple way but works :)
Sub Fx()
Dim str_Tab() As String, str_Text As String, str_Result As String
Dim int_Counter As Integer, int_TabItemCounter As Integer, int_LastRow As Integer
Dim rng_WorkRange As Range
int_LastRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
Set rng_WorkRange = ActiveSheet.Range("A1:A" & int_LastRow)
For i = 1 To int_LastRow
str_Text = ActiveSheet.Range("A" & i)
If i > 1 Then
str_Result = IsInArray(str_Text, str_Tab)
If str_Result = -1 Then
int_TabItemCounter = UBound(str_Tab) - LBound(str_Tab)
ReDim str_Tab(int_TabItemCounter)
str_Tab(int_TabItemCounter) = str_Text
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
Else
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
End If ' If str_Result = -1
Else ' If i > 1
ReDim str_Tab(i)
str_Tab(i) = str_Text
ActiveSheet.Range("B" & i) = CountThisItem(rng_WorkRange, str_Text)
End If ' If i > 1
Next i
End Sub
function to check is text in table
Function IsInArray(stringToBeFound As String, arr As Variant) As Long
Dim i As Long
' default return value if value not found in array
IsInArray = -1
For i = LBound(arr) To UBound(arr)
If StrComp(stringToBeFound, arr(i), vbTextCompare) = 0 Then
IsInArray = i
Exit For
End If
Next i
End Function
function to count item in range
Function CountThisItem(CountingRange As Range, a As String) As Integer
Dim rng_FindRange As Range
Dim LA As String
Set rng_FindRange = CountingRange.Find(a, lookat:=xlWhole)
If Not rng_FindRange Is Nothing Then
LA = rng_FindRange.Address
CountThisItem = 1
Do
Set rng_FindRange = CountingRange.Find(a, lookat:=xlWhole, after:=rng_FindRange)
If Not rng_FindRange Is Nothing And rng_FindRange.Address <> LA Then CountThisItem = CountThisItem + 1
Loop While rng_FindRange.Address <> LA
Else
CountThisItem = 0
End If
End Function
I have 3 sheets: DATA, BUILD and RESULT.
DATA - contains all data
BUILD - 1 row that is iterated through VBA procedure (below) and a command button.
RESULT - where I need to put every iterated row of BUILD table.
The following part of the code is expected to add new row to a RESULTS table.
In a RESULTS sheet, rows are copied sometimes in row 2567, sometimes in 237 etc.
I can't understand the logic how VBA determines the row it puts copied rows.
Sheets("RESULTS").Range("A2" & i + 1).Value = Sheets("BUILD").Range("D4").Value 'League Name
Sheets("RESULTS").Range("B2" & i + 1).Value = Sheets("BUILD").Range("E4").Value 'Home Team
Sheets("RESULTS").Range("C2" & i + 1).Value = Sheets("BUILD").Range("F4").Value 'Away Team
This is the full code:
Sub btn_NextMatch()
Application.ScreenUpdating = False
Application.Volatile
Dim Last_row As Double
Dim Last_Col As Integer
Dim i As Integer
Dim sheet As String
sheet = ActiveSheet.Name
Sheets("BUILD").Select
i = Range("A1").Value
Sheets("DATA").Select
Last_row = Range("A" & Rows.Count).End(xlUp).Row
Last_Col = ActiveSheet.Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, LookIn:=xlValues).Column
Last_colletter = Split(Cells(1, Last_Col).Address, "$")(1)
If i = Last_row Then
i = 1
End If
Sheets("BUILD").Range("C2").Value = Sheets("DATA").Range("C" & i + 1).Value 'MatchID
Sheets("BUILD").Range("D4").Value = Sheets("DATA").Range("D" & i + 1).Value 'League Name
Sheets("BUILD").Range("E4").Value = Sheets("DATA").Range("F" & i + 1).Value 'Home Team
Sheets("BUILD").Range("F4").Value = Sheets("DATA").Range("G" & i + 1).Value 'Away Team
Sheets("BUILD").Select
If i = Last_row Then
Range("A1").Value = 1
Else
Range("A1").Value = i + 1
Sheets("RESULTS").Range("A2" & i + 1).Value = Sheets("BUILD").Range("D4").Value 'League Name
Sheets("RESULTS").Range("B2" & i + 1).Value = Sheets("BUILD").Range("E4").Value 'Home Team
Sheets("RESULTS").Range("C2" & i + 1).Value = Sheets("BUILD").Range("F4").Value 'Away Team
End If
Application.ScreenUpdating = True
Sheets(sheet).Select
End Sub
I do not recommend using offset to counter the previous problem. Here are a few items corrected in the code:
Declare last row, column, etc as Long. There are over 1 million rows in Excel and integer will only handle up to 32,767. After that you will overload the value.
Shorten the workbook names by setting them as variables. No need to Dim as string.
Avoid Select and Activate by qualifying your worksheets and variables. That means giving as full information as needed to specify the location ThisWorkbook.Worksheets("Sheet1").Range("A1") versus Range("A1") that could be any sheet. Not only will this ensure proper locations, but will speed up your code by avoiding changing sheets.
Sub btn_NextMatch()
Application.ScreenUpdating = False
Application.Volatile
Dim Last_row As Long
Dim Last_Col As Long
Dim i As Long
Dim wks1 As Worksheet
Dim wks2 As Worksheet
Dim wks3 As Worksheet
Set wks1 = ThisWorkbook.Worksheets("BUILD")
Set wks2 = ThisWorkbook.Worksheets("DATA")
Set wks3 = ThisWorkbook.Worksheets("RESULTS")
i = wks1.Range("A1").Value
Last_row = wks2.Range("A" & Rows.Count).End(xlUp).Row
Last_Col = wks2.Cells.Find(What:="*", SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, LookIn:=xlValues).Column
Last_colletter = Split(wks2.Cells(1, Last_Col).Address, "$")(1)
If i = Last_row Then
i = 1
End If
wks1.Range("C2").Value = wks2.Range("C" & i + 1).Value 'MatchID
wks1.Range("D4").Value = wks2.Range("D" & i + 1).Value 'League Name
wks1.Range("E4").Value = wks2.Range("F" & i + 1).Value 'Home Team
wks1.Range("F4").Value = wks2.Range("G" & i + 1).Value 'Away Team
If i = Last_row Then
wks1.Range("A1").Value = 1
Else
wks1.Range("A1").Value = i + 1
wks3.Range("A" & i + 1).Value = wks1.Range("D4").Value 'League Name
wks3.Range("B" & i + 1).Value = wks1.Range("E4").Value 'Home Team
wks3.Range("C" & i + 1).Value = wks1.Range("F4").Value 'Away Team
End If
Application.ScreenUpdating = True
End sub
Darrel H. is right. If you are concatenating the iteration you're on to the cell address you are doing equivalent of: "A2" & 25 becomes A225, where you really wanted to have "A27". A way around this is to use the offset function. Your code rewritten would be like this:
Sheets("RESULTS").Range("A2" & i + 1).offset(rowoffset:=i + 1).value = Sheets("BUILD").Range("D4").Value 'League Name'
I have two sheets in my excel workbook.
Contained in these sheets are my primary key columns.
I want to compare the first column (which is the master) to the second column (source) using a VBA loop.
The reason is because the source usually contains new primary keys.
Please can anyone be kind enough to help me figure out a logic to compare these columns and add the unique values to the master column.
Thank you.
this image shows the sample master code
this image shows the sample source code
The code below shows what I have so far
Sub PullUniques()
Dim rngCell As Range
For Each rngCell In Sheet1.Range("W3:W40")
If WorksheetFunction.CountIf(Range("D3:D40"), rngCell) = 0 Then
Range("C" & Rows.Count).End(xlUp).Offset(1) = rngCell
End If
Next
For Each rngCell In Sheet6.Range("D3:D40")
If WorksheetFunction.CountIf(Range("W3:W40"), rngCell) = 0 Then
Range("W" & Rows.Count).End(xlUp).Offset(1) = rngCell
End If
Next
End Sub
Try this code, please. It is based on the assumption that in source sheet there could be keys not existing in your "Master" sheet, which will be add on the first empty row of the master sheet.
Sub testMasterUpdate()
Dim shM As Worksheet, shS As Worksheet, s As Long, boolF As Boolean
Dim lastRM As Long, lastRS As Long, m As Long
Dim arrM As Variant, arrS As Variant, arrDif As Variant, d As Long
Set shM = Worksheets("Master") 'please, use here your sheet name
Set shS = Worksheets("Source") 'please, use here your sheet name
lastRM = shM.Range("A" & Cells.Rows.Count).End(xlUp).Row
lastRS = shS.Range("A" & Cells.Rows.Count).End(xlUp).Row
arrM = shM.Range("A2:A" & lastRM).value
arrS = shS.Range("A2:A" & lastRS).value
ReDim arrDif(1 To 1, 1 To UBound(arrM) + UBound(arrS)): d = 1
For s = 1 To UBound(arrS)
For m = 1 To UBound(arrM)
If arrS(s, 1) = arrM(m, 1) Then
boolF = True
Exit For
End If
Next m
If Not boolF Then
arrDif(1, d) = arrS(s, 1)
d = d + 1
End If
boolF = False
Next s
If d > 1 Then
ReDim Preserve arrDif(1 To 1, 1 To d - 1)
'shM.Range("A" & lastRM + 1).Resize(UBound(arrDif, 2), 1).value = _
WorksheetFunction.Transpose(arrDif)
shM.Range("A" & lastRM).Resize(UBound(arrDif, 2), 1).value = _
WorksheetFunction.Transpose(arrDif)
lastRM = shM.Range("A" & Cells.Rows.Count).End(xlUp).Row
shM.Range("A" & lastRM + 1).Formula = "=CountA(A2:A" & lastRM & ")"
End If
End Sub
Please, replace generic sheet names with your real ones.
I am trying to identify a specific range in column-A and concatenate two cells within the specific range and delete the empty cell. I have been successful in putting a code together and it does the job very well. But, I don't know how to loop it to identify next range. Any help would be appreciated.
As per below image and code, First, I am finding and selecting a range between two (MCS) in column-A with a condition that, if the rows are more than 8 between two MCS. Then I am concatenating first 2 cells immediately after MCS and delete the empty row.
The below code works well for first range but I am unable to loop to identify next range from row 22 to 32 and perform concatenations. I want to loop in column-A as there will be more MCS.
Sub MergeStem()
Dim findMCS1 As Long
Dim findMCS2 As Long
Dim myCount As Integer
Dim myStems As Long
Dim mySelect As Range
Dim c As Range
findMCS1 = Range("A:A").Find("MCS", Range("A1")).Row
findMCS2 = Range("A:A").Find("MCS", Range("A" & findMCS1)).Row
myCount = Range("A" & findMCS1 + 1 & ":A" & findMCS2 - 1).Cells.Count
Range("B1").Value = myCount
MsgBox "Number of rows =" & myCount
Set mySelect = Selection
If myCount > 8 Then
myStems = Range("A" & findMCS1 + 2 & ":A" & findMCS2 - 9).Select
Set mySelect = Selection
For Each c In mySelect.Cells
If firstcell = "" Then firstcell = c.Address(bRow, bCol)
sArgs = sArgs + c.Text + " "
c.Value = ""
Next
Range(firstcell).Value = sArgs
End If
Columns("A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Application.ScreenUpdating = True
End Sub
You could try:
Option Explicit
Sub test()
Dim i As Long, Lastrow As Long, Startpoint As Long, Endpoint As Long, Diff As Long
Dim str As String
With ThisWorkbook.Worksheets("Sheet1")
Lastrow = .Cells(.Rows.Count, "A").End(xlUp).Row
Startpoint = 0
Endpoint = 0
For i = Lastrow To 2 Step -1
str = .Range("A" & i).Value
If str = "MCS" And Startpoint = 0 Then
Startpoint = i
ElseIf str = "MCS" And Startpoint <> 0 Then
Endpoint = i
End If
If Startpoint > 0 And Endpoint > 0 Then
Diff = Startpoint - Endpoint
If Diff > 8 Then
.Range("A" & Endpoint + 1).Value = .Range("A" & Endpoint + 1).Value & " " & .Range("A" & Endpoint + 2).Value
.Rows(Endpoint + 2).EntireRow.Delete
Startpoint = 0
Endpoint = 0
End If
End If
Next i
End With
End Sub
I have created this procedure which works fine for cleaning blank cells in column AF. I want to modify this to pass on the column number as a variable so i can use the same procedure for other columns.
Column Z is my temp working column.
any ideas?
Private Sub clean_com_cells()
Dim counter As Integer, i As Integer, lastrow As Integer
lastrow = Mysheet.Range("AF65536").End(xlUp).Row
counter = 0
For i = 1 To lastrow
If Mysheet.Cells(i, 32).Value <> "" Then
Mysheet.Cells(counter + 1, 26).Value = Mysheet.Cells(i, 32).Value
counter = counter + 1
End If
Next i
Mysheet.Range("AF1:AF" & lastrow).Value = ""
Mysheet.Range("AF1:AF" & lastrow).Value = Mysheet.Range("Z1:Z" & lastrow).Value
Mysheet.Range("Z1:Z" & lastrow).Value = ""
End Sub
This is not how I would have done what you're trying to do, but this allows you to parameterize the column number that you're trying to "clear". I think that it would help to explain what you're trying to accomplish more explicitly, but this code should get you what you need. Note, you need lastrow to be a Long since Integers only go from -32k to 32k (approx). FYI, Longs perform better than Integers in recent versions of VBA, since Integers get converted to Longs. Never use Integers. Bytes, on the other hand, do perform better if your data fits that profile (0 to 255).
Private Sub clean_com_cells(column_number as integer)
Dim counter As Integer, i As Integer, lastrow As long
Dim clear_rng as range
lastrow = Mysheet.cells(65536,column_number).End(xlUp).Row
counter = 0
For i = 1 To lastrow
If Mysheet.Cells(i, column_number).Value <> "" Then
Mysheet.Cells(counter + 1, 26).Value = Mysheet.Cells(i, column_number).Value
counter = counter + 1
End If
Next i
with mysheet
set clear_rng = Range(.cells(1,column_number), .cells(lastrow,column_number))
clear_rng.Value = .Range("Z1:Z" & lastrow).Value
Mysheet.Range("Z1:Z" & lastrow).Value = ""
end with
End Sub
You can adjust the function to take an input parameter, which I've named TargetColNumber below. I also added handy function for finding the last row in a worksheet... a future refactor might involve passing a Worksheet to the cleaning routine.
Anyway, call the function with a number and you should be good to...
Option Explicit
'this is the routine that cleans your cells
Sub clean_com_cells_in_col(TargetColNumber As Long)
Dim counter As Long, i As Long, lastrow As Long
Dim MySheet As Worksheet
Set MySheet = ThisWorkbook.ActiveSheet
lastrow = FindLastRow(MySheet)
counter = 0
For i = 1 To lastrow
If MySheet.Cells(i, TargetColNumber).Value <> "" Then
MySheet.Cells(counter + 1, 26).Value = MySheet.Cells(i, TargetColNumber).Value
counter = counter + 1
End If
Next i
With MySheet
.Range(.Cells(1, TargetColNumber), .Cells(lastrow, TargetColNumber)).Value = ""
.Range(.Cells(1, TargetColNumber), .Cells(lastrow, TargetColNumber)).Value = _
.Range(.Cells(1, 26), .Cells(lastrow, 26)).Value
.Range(.Cells(1, 26), .Cells(lastrow, 26)).Value = ""
End With
End Sub
'we'll use this function to identify the last row in a worksheet
Public Function FindLastRow(flrSheet As Worksheet) As Long
If Application.WorksheetFunction.CountA(flrSheet.Cells) <> 0 Then
FindLastRow = flrSheet.Cells.Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
Else
FindLastRow = 1
End If
End Function
'this is our test
Sub TestItYall()
Call clean_com_cells_in_col(4) '<~ did it work?
End Sub
You can use a string variable for you column like you have done with lastrow. Example here uses a variable called "col":
Private Sub clean_com_cells()
Dim counter As Integer, i As Integer, lastrow As Integer,col as string
col = "AF" 'Change this to vary the column
lastrow = Mysheet.Range(col & "65536").End(xlUp).Row
counter = 0
For i = 1 To lastrow
If Mysheet.Cells(i, 32).Value <> "" Then
Mysheet.Cells(counter + 1, 26).Value = Mysheet.Cells(i, 32).Value
counter = counter + 1
End If
Next i
Mysheet.Range(col & "1:" & col & lastrow).Value = ""
Mysheet.Range(col & "1:" & col & lastrow).Value = Mysheet.Range("Z1:Z" & lastrow).Value
Mysheet.Range("Z1:Z" & lastrow).Value = ""
End Sub