Fast Stack-Columns and Transpose - vba

After few days learning VBA, I managed to get a simple macro to take some data from a sheet and transpose to another, then stack the columns together.
Macro
Sub pivotsourcedata()
Dim HeaderSelect As Range
Dim DataSelect As Range
Dim ID As Range
'Variabile Declaration for Progress bar
Dim x As Integer
Dim MyTimer As Double
For i = 1 To 7589
'Progress bar
Application.StatusBar = "Progress: " & i & " of 7589: " & Format(i / 7589, "0%")
'Copy ID Range
Sheets("Opps Closed FY15").Select
Range("A13").Offset(i, 0).Select
Set ID = Selection
'Copy Header Range
Range("EX13:HA13").Select
Set HeaderSelect = Selection
'Copy Data Range
Range("EX13:HA13").Offset(i, 0).Select
Set DataSelect = Selection
'Select ID and copy it to the next sheet and fill it down
ID.Copy
Sheets("Sheet1").Select
If i = 1 Then
Else
Selection.Resize(1, 1).Offset(0, 1).Select
End If
Selection.PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Selection.Resize(HeaderSelect.Columns.Count).FillDown
'Select the Header, copy it in the adjacent column
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
Sheets("Opps Closed FY15").Select
HeaderSelect.Copy
Sheets("Sheet1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'Same for the data, copy to the right of Header
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
Sheets("Opps Closed FY15").Select
DataSelect.Copy
Sheets("Sheet1").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
'Stack the columns one over the other 3 by 3.
' take the 4th, 5th and 6th columns and stuck'em
' below 1st, 2nd and 3rd
If i = 1 Then
Else
Range("A1:C1").Offset(56 * (i - 1), 0).Resize(56, 3).Select
Dim PasteSelect As Range
Set PasteSelect = Selection
Range("D1:F56").Select
Selection.Cut Destination:=PasteSelect
Selection.Resize(1, 1).Offset(0, -1).Select
End If
Next i
Application.StatusBar = False
End Sub
As you can see for each of the 7589 times, I copy and transpose 3 times a range of 56 columns. This is taking a while, around 1.5h. Since I need to run it every week, I'm asking if I wrote badly some code portions...maybe I don't know I can seed it up in some areas...
any thoughts?
Update
After yours suggestions i get to tune up a bit the code, I'd like to know if there are others "imperfections"
Sub pivotsourcedata()
Dim OppsClosed As Worksheet
Set OppsClosed = Worksheets("Opps Closed FY15")
Dim Shadow2 As Worksheet
Set Shadow2 = Worksheets("Shadow2")
Dim ID As Range
Dim ID0 As Range
Set ID0 = OppsClosed.Range("A14")
Dim HeaderSelect As Range
Set HeaderSelect = OppsClosed.Range("EX13:HA13")
Dim DataSelect As Range
Set DataSelect = HeaderSelect
Dim PasteSelect As Range
Dim PasteSelect0 As Range
Set PasteSelect0 = Shadow2.Range("A1:C1").Resize(56, 3)
Dim CopySelect As Range
Set CopySelect = Shadow2.Range("D1:F56")
Dim Inizialize As Range
Set Inizialize = Shadow2.Range("D1:D1")
'Variabile Declaration for Progress bar
Dim x As Integer
Dim MyTimer As Double
'Set ScreenUpdating to False
Application.ScreenUpdating = False
For i = 1 To 7589
'Progress bar
Application.StatusBar = "Progress: " & i & " of 7589: " & Format(i / 7589, "0%")
'Copy ID Range
Set ID = ID0.Offset(i, 0)
'Copy Data Range
Set DataSelect = HeaderSelect.Offset(i, 0)
'Select ID and copy it to the next sheet and fill it down
ID.Copy
Shadow2.Select
If i = 1 Then
Range("A1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("A1").Resize(HeaderSelect.Columns.Count).FillDown
Else
Range("D1").PasteSpecial Paste:=xlPasteAll, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Range("D1").Resize(HeaderSelect.Columns.Count).FillDown
End If
'Select the Header, copy it in the adiacent column
HeaderSelect.Copy
If i = 1 Then
Shadow2.Range("B1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Else
Shadow2.Range("E1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
End If
'Same for the data, copy to the right of Header
DataSelect.Copy
If i = 1 Then
Shadow2.Range("C1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
Else
Shadow2.Range("F1").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:= _
False, Transpose:=True
End If
'Stack the columns one over the other 3 by 3.
' take the 4th, 5th and 6th columns and stuck'em
' below 1st, 2nd and 3rd
If i = 1 Then
Else
Set PasteSelect = PasteSelect0.Offset(HeaderSelect.Columns.Count * (i - 1), 0)
Shadow2.Range("D1:F56").Cut Destination:=PasteSelect
End If
Next i
Application.StatusBar = False660858
'Set ScreenUpdating to True
Application.ScreenUpdating = True
End Sub

Take a look at this link for several other things that you can turn off, such as formula recalculation: http://datapigtechnologies.com/blog/index.php/ten-things-you-can-do-to-speed-up-your-excel-vba-code/
I agree that the multiple selects are unnecessary and likely slowing down the code significantly. In many cases, they can simply be combined - as in using
Selection.Resize(1, 1).Offset(0, 1).Select
instead of
Selection.Resize(1, 1).Select
Selection.Offset(0, 1).Select
But also, why not reference your ranges explicitly using your counter value, and avoid using resize and offset so frequently?
Another thought is to see if you can remove the final operation that stacks the columns after they are pasted to a new sheet - would it be possible to rearrange your source data, perhaps at the top of your macro before you get into the loop? That way you would have to perform that stacking once instead of 7589 times. Or, alternatively, find a way to combine the columns after the end of the loop.

The answer to my question was: "Use arrays" :)
The code now is this:
Sub pivotsourcedata()
'Set ScreenUpdating to False
Application.ScreenUpdating = False
Application.StatusBar = True
Dim OppsClosed As Worksheet
Set OppsClosed = Worksheets("Opps Closed FY15")
Sheets.Add.Name = "Shadow2"
Dim Shadow2 As Worksheet
Set Shadow2 = Worksheets("Shadow2")
Dim ID As Range
Dim ID0 As Range
Set ID0 = OppsClosed.Range("A13")
Dim HeaderSelect As Range
Set HeaderSelect = OppsClosed.Range("FB1")
Dim DataSelect As Range
Set DataSelect = OppsClosed.Range("FC14")
Dim RowSize As Integer
OppsClosed.Activate
Dim lastrow, records, nHeader As Integer
lastrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row - 13
nHeader = 56
records = lastrow * nHeader
'Stack DataSelect on column C of Shadow 2
ReDim TempTableData(1 To nHeader, 1 To lastrow) As Variant
ReDim TempTableHeader(1 To nHeader, 1 To lastrow)
ReDim FixedHeaders(1 To nHeader, 1 To 1)
ReDim Temp_Array1(1 To records, 1 To 1) As Variant
ReDim Temp_Array2(1 To records, 1 To 1) As Variant
FixedHeaders = OppsClosed.Range("FC1").Resize(1, nHeader)
FixedHeaders = Application.Transpose(FixedHeaders)
For j = 1 To lastrow
'Progress bar
Application.StatusBar = "Progress: " & j & " of " & lastrow & ": " & Format(j / lastrow, "0%")
For i = 1 To nHeader
TempTableData(i, j) = DataSelect.Offset(j - 1, i - 1)
TempTableHeader(i, j) = FixedHeaders(i, 1)
Next i
Next j
For j = 1 To nHeader
For i = 0 To lastrow - 1
Temp_Array1((i * nHeader) + j, 1) = TempTableData(j, i + 1)
Temp_Array2((i * nHeader) + j, 1) = TempTableHeader(j, i + 1)
Next i
Next j
Shadow2.Range("C1:C" & records).Value2 = Temp_Array1
Shadow2.Range("B1:B" & records).Value2 = Temp_Array2
'Copy and Replicate ID
ReDim TempTableID(1 To records, 1 To 1)
k = 1
For i = 1 To records
'Progress bar
Application.StatusBar = "Progress: " & i & " of " & records & ": " & Format(i / records, "0%")
DoEvents
'FixedID = OppsClosed.Range("A13").Offset(k, 0)
TempTableID(i, 1) = OppsClosed.Range("A13").Offset(k, 0)
variable = i / nHeader
If Fix(variable) = variable Then
k = k + 1
End If
Next i
Shadow2.Range("A1:A" & records).Value2 = TempTableID
Application.StatusBar = False
Application.ScreenUpdating = True
End Sub

Related

Adjusting the range per iteration in a Macro VBA

I have a huge dataset consisting of multiple choice questions, which have to be sorted. Each question consists of a group of 10 rows, which has to be transformed into 10 columns. The sheet is now 1100 rows and I will have to do this with 16 other sheets of the same format.
I have created a macro in Excel by recording the necessary actions which result in this line of code:
Selection.End(xlDown).Select
Range("C21:C26").Select
Selection.Copy
Range("C19").Select
Selection.PasteSpecial Paste:=xlAll, Operation:=xlNone, SkipBlanks:=False _
, Transpose:=True
Rows("21:31").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
Range("B27").Select
End Sub
Now I need the variables in the macro to change +1 each iteration, so the next iteration it will look like this.
Selection.End(xlDown).Select
Range("C22:C27").Select
Selection.Copy
Range("C20").Select
Selection.PasteSpecial Paste:=xlAll, Operation:=xlNone, SkipBlanks:=False _
, Transpose:=True
Rows("22:32").Select
Application.CutCopyMode = False
Selection.Delete Shift:=xlUp
Range("B28").Select
End Sub
I'm completely stuck there. Help is greatly appreciated!
Thanks so much in advance.
So I am a little unclear on your row counts.
You might be able to use arrays as follows (be sure to back up sheet as this clears data from the sheet)
Option Explicit
Public Sub Test()
Dim startRow As Long, endRow As Long, rng As Range, arr(), outputArr(), i As Long
startRow = 21
endRow = 1100
With ThisWorkbook.Worksheets("SheetA") '<== Change as required
Set rng = .Range("C" & startRow & ":C" & endRow)
arr = rng.Value
arr = Application.WorksheetFunction.Transpose(Application.WorksheetFunction.Index(arr, 0, 1))
ReDim outputArr(1 To 5, 1 To Application.WorksheetFunction.RoundUp(UBound(arr, 1) / 5, 0))
outputArr = Application.WorksheetFunction.Transpose(outputArr)
Dim counter As Long, counter2 As Long
counter2 = 1
For i = LBound(arr) To UBound(arr) Step 12
For counter = 0 To 4
outputArr(counter2, counter + 1) = arr(i + counter)
Next
counter2 = counter2 + 1
Next
rng.ClearContents
.Range("C19").Resize(UBound(outputArr, 1), UBound(outputArr, 2)) = outputArr
End With
End Sub

Copy & Paste into next empty row & column respectively

I asked a number of times on this question & all the while, I being given vague answer, which isn't much help. Thus I just research on my own and came up with the following code from my research. Which works but doesn't exactly give me the desired outcome stated in the image attached. Whereby the codes paste the data from its specified cells but paste in column A which isn't the outcome wanted, but rather to paste from column B onward for sheets DX,DY & DZ.
Is there also a way I can get column A to update the date by itself base on Date entered in cell S9 which tag along with the data for sheets DX,DY & DZ. Likewise for sheet RAW, that update row 6 with the date entered in S9 of sheet GP Data
Sub Prism2ndStep()
'
' Prism2ndStep Macro
'
r = 1
Sheets("GP Data").Range("S12:S14").Copy
If Sheets("GP Data").Range("S12") = Sheets("DX").Range("A65536").End(xlUp) _
Then r = 0
Sheets("DX").Range("A65536").End(xlUp).Offset(r, 0).PasteSpecial _
Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
j = 1
Sheets("GP Data").Range("T12:T14").Copy
If Sheets("GP Data").Range("T12") = Sheets("DX").Range("A65536").End(xlUp) _
Then j = 0
Sheets("DX").Range("A65536").End(xlUp).Offset(j, 0).PasteSpecial _
Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
k = 1
Sheets("GP Data").Range("U12:U14").Copy
If Sheets("GP Data").Range("U12") = Sheets("DX").Range("A65536").End(xlUp) _
Then k = 0
Sheets("DX").Range("A65536").End(xlUp).Offset(k, 0).PasteSpecial _
Paste:=xlPasteValues, Transpose:=True
Application.CutCopyMode = False
Dim copySheet As Worksheet
Dim pasteSheet As Worksheet
Set copySheet = Worksheets("GP Data")
Set pasteSheet = Worksheets("RAW")
copySheet.Range("P12:R14").Copy
With pasteSheet
.Cells(7, .Columns.Count).End(xlToLeft).Offset(0, 7).PasteSpecial _
Paste:=xlPasteValues, Operation:=xlNone, _
SkipBlanks:=False, Transpose:=False
End With
End Sub
Try this macro for copying data from "GP Data" S12:S14 and pasting it into column B:D in DX tab.
Edited
Sub prism2ndStep()
'get date from cell p9
strdate = Sheets("GP Data").Range("S9").Value
arrData = Sheets("GP Data").Range("S12:S14").Value
Set rngwrite = Nothing
Set rngwrite = Sheets("DX").Range("A:A").Find(strdate, LookIn:=xlFormulas)
Do While rngwrite Is Nothing
With Sheets("DX").Range("A60000")
.End(xlUp).AutoFill (.End(xlUp).Resize(2))
End With
Set rngwrite = Sheets("DX").Range("A:A").Find(CDate(strdate), LookIn:=xlFormulas)
Loop
rngwrite.Offset(, 1).Resize(, 3).Value = Application.Transpose(arrData)
End Sub
Sub prism2ndStep2()
'get data
arrData = Sheets("GP Data").Range("P12:R14").Value
'find get the first non-blank column in row 7 from right to left
Set rngwrite = Sheets("RAW").Range("IV7").End(xlToLeft).Offset(, 1)
'paste data
rngwrite.Resize(3, 3).Value = arrData
'drag dates across row 7
rngwrite.Offset(-1).Value = rngwrite.Offset(-1, -3).Value + 1
End Sub

VBA: Build a Table by (Copy/Paste) by Using Criteria to Select Rows, Then Specifiy Columns

I want to build a table on one Excel Sheet "Ship" by pulling data from another excel sheet "Efficiency." The row data on the "Efficiency" sheet is categorized by "Shipped", "Leave", "Import" and "Export".
Each category (shipped, leave, import, export) has several items and they're in no specific order. The table on the "Efficiency" sheet occupies columns A:H, and starts at row 2; the length can vary.
I want to be able to search the rows for "Shipped" and copy columns A, D:F and H of the matching rows and paste them beginning at cell B4 of the "Ship" sheet. Can anyone help me please?
Sub Ship()
ActiveSheet.Range("$A$1:$H$201").AutoFilter Field:=4, Criteria1:="Shipped"
' this is looking in a specific range, I want to make it more dynamic
Range("A4:A109").Select
'This is the range selected to copy, again I want to make this part more dynamic
Application.CutCopyMode = False
Selection.Copy
Range("A4:A109,D4:F109,H4:H109").Select
Range("G4").Activate
Application.CutCopyMode = False
Selection.Copy
Sheets("Ship").Select
Range("B4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
This code has been tested based on your the information as given in your question:
Sub Ship()
Dim wsEff As Worksheet
Dim wsShip As Worksheet
Set wsEff = Worksheets("Efficiency")
Set wsShip = Worksheets("Shipped")
With wsEff
Dim lRow As Long
'make it dynamic by always finding last row with data
lRow = .Range("A" & .Rows.Count).End(xlUp).Row
'changed field to 2 based on your above comment that Shipped is in column B (the code you posted has 4).
.Range("A1:H" & lRow).AutoFilter Field:=2, Criteria1:="Shipped"
Dim rngCopy As Range
'only columns A, D:F, H
Set rngCopy = Union(.Columns("A"), .Columns("D:F"), .Columns("H"))
'filtered rows, not including header row - assumes row 1 is headers
Set rngCopy = Intersect(rngCopy, .Range("A1:H" & lRow), .Range("A1:H" & lRow).Offset(1)).SpecialCells(xlCellTypeVisible)
rngCopy.Copy
End With
wsShip.Range("B4").PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End Sub
try the below code
Sub runthiscode()
Worksheets("Efficiency").Select
lastrow = Range("A" & Rows.Count).End(xlUp).Row
startingrow = 4
For i = 2 To lastrow
If Cells(i, 2) = "Shipped" Then
cella = Cells(i, 1)
celld = Cells(i, 4)
celle = Cells(i, 5)
cellf = Cells(i, 6)
cellh = Cells(i, 8)
Worksheets("Ship").Cells(startingrow, 2) = cella
Worksheets("Ship").Cells(startingrow, 5) = celld
Worksheets("Ship").Cells(startingrow, 6) = celle
Worksheets("Ship").Cells(startingrow, 7) = cellf
Worksheets("Ship").Cells(startingrow, 9) = cellh
startingrow = startingrow + 1
End If
Next i
End Sub

Looping a cut and paste if criteria is met

I am trying to loop the following
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
Once this cell AE4 has been checked and then copied or not depeding of it is greater or = to AD4 i would like this to then move on to AE5, AE6 etc to the end of the data set. any ideas what i need to do next? I currently have the rest of the script executed before this checking iof the a cell date is below 4 weeks and then 5 weeks, 6 weeks old up to 10 weeks. and is currenlty working as expected checking the date of the cell and then checking and copying the first cell in the data.
Full script is as follows.
Sub Test()
Range("AE4").Select
ActiveCell.Formula = _
"=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
Range("AE4").Select
Selection.AutoFill Destination:=Range("AE4:AE200")
Range("AE4:AE200").Select
Dim x As Integer
Dim y As Integer
x = Range("AE4")
y = Range("AD4")
If x >= y Then
Range("AE4").Select
Selection.Copy
Range("AD4").Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Else
End If
End Sub
Below is some code that'll do what I think you're asking. It looks as though you're relying on the macro generator quite heavily which tends to 'select' a lot more than a developer needs to do. Have a play with your code and look at other posts to see how others do it.
Sub Test()
Dim ws As Worksheet
Dim startCell as Range
Dim fullRng As Range
Dim thisCell As Range
Dim leftCell as Range
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set startCell = ws.Range("AE4")
Set fullRng = startCell.Resize(196)
startCell.Formula = "=IF(RC[-2]>=TODAY()-28,""1"",IF(AND(RC[-2]<TODAY()-28,RC[-2]>=TODAY()-35),""4"",IF(AND(RC[-2]<TODAY()-35,RC[-2]>=TODAY()-42),""5"",IF(AND(RC[-2]<TODAY()-42,RC[-2]>=TODAY()-49),""6"",IF(AND(RC[-2]<TODAY()-49,RC[-2]>=TODAY()-56),""7"",IF(AND(RC[-2]<TODAY()-56,RC[-2]>=TODAY()-63),""8"",IF(AND(RC[-2]<TODAY()-63,RC[-2]>=TODAY()-70),""9"",IF(RC[-2]<TODAY()-70,""10""))))))))"
startCell.AutoFill fullRng
For Each thisCell In fullRng.Cells
Set leftCell = thisCell.Offset(, -1)
Debug.Print("Before If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
If thisCell.Value2 >= leftCell.Value2 Then
leftCell.Value2 = cell.Value2
Debug.Print("After If: " & thisCell.Address(False, False) & "=" & thisCell.Value2 & " v. " & leftCell.Address(False, False) & "=" & leftCell.Value2)
End If
Next
End Sub
Easiest way is probably a lopp that just repeats what you are doing.
Instead of defining x and y as ranges, you would only need a count variable:
dim lastrow as integer
lastrow = Cells(Rows.count, "AE").End(xlUp).row 'counts the amount of cells you have with values in the row
for i = 2 to lastrow 'set 2 = whatever, but I guess you have header rows, if you want to start in the 4th row set it 4
if CELLS(i,31).Value >= CELLS(i,30).Value THEN 'the cell commands uses 1-indexed numbers to refer to cells on an x-y axis, rows go on the x axis so Cells(2,1) is "B1" for some reason.
'insert your loop here
Cells(i,31).Select
Selection.Copy
Cells(i,30).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
End if
Next i

To copy number of values present in workbook1 ("A") to the work book 2 of coloumn B: VBA

I wanted to do like this:
Work Book1 (
Sheet1 has:
ColA:
AA
AA
AA
AB
AB
AB
AC
AC
AC
AC
Now I need to count how many are AA's, AB's, AC's and so on and represent their numbers in ColB of Work book B (Sheet1) like this:
ColA: ColB:
AA 3
AB 3
AC 4
Here in this second work book Col A is already mentoined so need to filter or add or change Col A just to update Col (B).
With the help of users here is the code modified so far: but I need your input thank you!
Code:
Sub foo()
Dim x As Workbook
Dim y As Workbook
'# Openning both workbooks first:
Set x = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book2")
Set y = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book1")
'Navigate to the first WOrkBook
Windows("Book1").Activate
'Find all the Rown in Range A that you need to copy
Sheets("Sheet1").Range("A1:A" & Sheets("Sheet1").Rows.Count).End(xlUp).Rows.Select
Selection.Copy
'Navigate to the Other WOrkBook
Windows("Book2").Activate
Sheets("Sheet2").Select
ActiveSheet.Paste
Application.CutCopyMode = False
'This will remove the Duplicates
ActiveSheet.Range("$A$1:$A$" & ActiveSheet.Rows.Count).End(xlUp).Rows.RemoveDuplicates Columns:=1, Header:=xlNo
Range("B1").Select
ActiveCell.FormulaR1C1 = "=COUNTIF([Book12]Sheet1!C1,RC[-1])"
Range("B1").Select
Selection.AutoFill Destination:=Range("B1:B" & Rows.Count).End(xlUp).Rows
Range("B1:B" & Rows.Count).End(xlUp).Rows.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Application.CutCopyMode = False
'Close x:
x.Close
End Sub
Here's how I'd do it, using the RemoveDuplicates function:
'# Opening both workbooks first:
Set x = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book2.xlsx")
Set y = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book1.xlsx")
'Navigate to the first WorkBook
x.Sheets(1).Activate
'Copy-Paste column A to y.sheets(1)
lastRow_x = Range("A" & Rows.Count).End(xlUp).Row
Range("A1:A" & lastRow_x).Copy
'Paste and remove duplicates
y.Sheets(1).Activate
Range("A1").PasteSpecial xlPasteValuesAndNumberFormats
Range("A:A").RemoveDuplicates Columns:=1, Header:=xlNo 'if your column has a header, use xlYes
'Count number of occurences of each row from y in x
lastRow_y = Range("A" & Rows.Count).End(xlUp).Row
For each loopCell in Range("A1:A" & lastRow_y) 'A2 if you have a header
loopCell.Offset(0, 1) = Sheets(1).Evaluate("=COUNTIF([Book2.xlsx]Sheet1!A1:A" & lastRow_x & "," & loopCell.Address & ")")
next loopCell
'Close x:
x.Close SaveChanges:=xlNo
End Sub
I haven't tested it but it should be really quick!
From my own experience, I would avoid using the .copy feature. Instead I recommend using an array to identify a unique list of items.
'# Openning both workbooks first:
Set x = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book2")
Set y = Workbooks.Open("C:\Users\ax1jk3\Desktop\Workbooks\Book1")
'Navigate to the first WOrkBook
Windows("Book1").Activate
Sheets("Sheet1").Select
'identify end of source tab
source_ROW = ActiveSheet.UsedRange.Row - 1 + ActiveSheet.UsedRange.Rows.Count
Do While Range("A" & source_ROW) = ""
source_ROW = source_ROW - 1
Loop
source_ROW_end = source_ROW
source_ROW_start = 3
'initialize unique value array
Dim unique_ARRAY() As String
ReDim unique_ARRAY(1 To 1)
unique_ARRAY(1) = Range("A" & source_ROW_start)
'identify unique list
For source_ROW = source_ROW_start To source_ROW_end
'initialize
source_record = Range("A" & source_ROW)
new_value = "dunno_yet"
For i = 1 To UBound(unique_ARRAY, 1)
If source_record = unique_ARRAY(i) Then
'value already exists in the array
new_value = "no"
'no need to continue searching
Exit For
End If
Next i
If new_value = "no" Then
'the source_record matched values already found in the array
'does nothing
Else
'a new source_record was found
'new_value = "yes"
'redimensionalize the array while preserving pre-existing values
ReDim Preserve unique_ARRAY(1 To UBound(unique_ARRAY) + 1)
'read the new value into the new upper bound of the array
unique_ARRAY(UBound(unique_ARRAY, 1)) = source_record
End If
Next source_ROW
'Navigate to the Other WOrkBook
Windows("Book2").Activate
Sheets("Sheet2").Select
'cycle through each item in the array
for i = 1 to UBound(unique_ARRAY)
'write values to book2
Range("A" & i) = unique_ARRAY(i)
Range("B" & i) = "=COUNTIF([Book1]Sheet1!C1,RC[-1])"
'convert formulas to values
Range("B" & i).Copy
Range("B" & i).PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False
next i
'Close x:
x.Close
End Sub
You may also consider adapting the array to count how many times a value appears. Then you can eliminate .PasteSpecial at the end.