[英]select each cell from a column and loop through a column in another workbook if it exists Excel VBA Macro
I have 2 workbooks called "Source1" and "Source2". 我有两个名为“ Source1”和“ Source2”的工作簿。
For each cell in the last column of "Source1" I check if it exists in the last column of "Source2". 对于“ Source1”的最后一列中的每个单元格,我检查它是否存在于“ Source2”的最后一列中。
If yes, then I copy 4 separate cells from that row based on some critea into a new workbook called "Target". 如果是,那么我将根据一些critea从该行中复制4个单独的单元格到一个名为“ Target”的新工作簿中。
My macro is working but as I have thousands of cells to loop through, it takes me at least 10 min till the macro finishes. 我的宏正在运行,但是由于我要遍历数千个单元,因此至少需要10分钟才能完成宏。 I am running it many times a day so I want to optimize my code so that it will take less time.
我一天要运行很多次,所以我想优化代码,以减少时间。
Here is my code 这是我的代码
Sub Loop_Cells()
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.SheetsInNewWorkbook = 1
Dim Source, Source2, Target As Workbook
Dim c As Range
Dim lRow, lRow2 As Long
Dim x, y, w As Integer
Set Source = Workbooks.Open("C:\Reports\Source1.xlsx")
Source.Activate
x = ActiveSheet.UsedRange.Columns.Count
ActiveSheet.Cells(1, x + 1) = "Concate"
lRow = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
ActiveSheet.Cells(i, x + 1).Value = ActiveSheet.Cells(i, 6).Value & ActiveSheet.Cells(i, 7).Value
Next i
ActiveSheet.Columns(x + 1).NumberFormat = "0"
Set Source2 = Workbooks.Open("C:\Reports\Source2.xlsx")
Source2.Activate
y = ActiveSheet.UsedRange.Columns.Count
ActiveSheet.Cells(1, y + 1) = "Concate"
lRow2 = ActiveSheet.Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow2
ActiveSheet.Cells(i, y + 1).Value = ActiveSheet.Cells(i, 48).Value & ActiveSheet.Cells(i, 3).Value
Next i
ActiveSheet.Columns(y + 1).NumberFormat = "0"
Set Target = Workbooks.Add
Target.Sheets(1).Name = "ExistCells"
Source.Sheets(1).Activate
w = 1
For Each c In Source1.Sheets(1).UsedRange.Columns(x + 1).Cells
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then
Target.Sheets(1).Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48).Value
Target.Sheets(1).Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3).Value
Target.Sheets(1).Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27).Value
Target.Sheets(1).Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41).Value
w = w + 1
End If
Next j
Next c
Workbooks("Source1.xlsx").Close SaveChanges:=False
Workbooks("Source1.xlsx").Close SaveChanges:=False
Target.Activate
ActiveWorkbook.SaveAs FileName:= "C:\Reports\Target.xlsx", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
I think the problem is in this part, when the cell exists I don't need to loop till the last row and I should move to the next. 我认为问题出在这部分,当单元存在时,我不需要循环到最后一行,而应该移至下一行。
For j = 2 To lRow2
对于j = 2到lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then ...如果c.Value = Source2.Sheets(1).Cells(j,y + 1).Value然后...
Any Suggestions how to adjust my code? 任何建议如何调整我的代码?
Collections are optimized for fast lookups. 集合已针对快速查找进行了优化。 For this reason,they are ideal when matching values.
因此,它们是匹配值时的理想选择。
Consider matching two lists each with 1000 values. 考虑匹配两个具有1000个值的列表。 Assuming that on average you find a match half way through the list, that's (500 * 1000) or 500K operations.
假设平均而言,您在列表的中间找到一个匹配项,即(500 * 1000)或500K运算。 Using a Collection would reduce the number to 1000 iterations + 1000 lookups.
使用Collection会将数量减少到1000次迭代+ 1000次查找。 Assuming that it takes 1 to 10 operations per lookup (just a guess) then you would reduce the number of operations that it takes to compare two 1000 element lists from 500K to 6K.
假设每次查找需要1到10个操作(只是一个猜测),那么您可以减少比较两个1000个元素列表(从500K到6K)所需的操作数量。
Once a match is found you write 4 values to the new worksheet. 找到匹配项后,您将4个值写入新工作表。 Let's say you find 1000 matches, that's 4000 write operations to the worksheet.
假设您找到1000个匹配项,即对工作表的4000个写操作。 If instaed you hold these values in an array and then write the array to the worksheet you'll reduce the number of write operations (to the worksheet) from 400 to 1.
如果立即将这些值保存在一个数组中,然后将该数组写入工作表,则将(对工作表的)写操作的数量从400减少到1。
Sub NewLoop()
Application.ScreenUpdating = False
Application.SheetsInNewWorkbook = 1
Dim data As Variant, result As Variant
Dim lastRow As Long, x As Long, x1 As Long
Dim key As String
Dim list As Object
Set list = CreateObject("System.Collections.ArrayList")
With Workbooks.Open("C:\Reports\Source1.xlsx")
With .Worksheets(1)
data = .Range("F2:G" & .Range("A" & Rows.Count).End(xlUp).Row).Value
For x = 1 To UBound(data, 1)
'Create a Unique Identifier using a pipe to delimit the data
'This will keep the data from mixing
key = data(x, 1) & "|" & data(x, 2)
If Not list.Contains(key) Then list.Add key
Next
End With
.Close SaveChanges:=False
End With
With Workbooks.Open("C:\Reports\Source2.xlsx")
With .Worksheets(1)
lastRow = .Range("A" & Rows.Count).End(xlUp).Row
ReDim result(1 To lastRow, 1 To 4)
For x = 2 To lastRow
'Create a Unique Identifier using a pipe to delimit the data
'This will keep the data from mixing
key = .Cells(i, 48).Value & "|" & .Cells(i, 3).Value
If list.Contains(key) Then
x1 = x1 + 1
result(x1, 1) = .Cells(j, 48).Value
result(x1, 2) = .Cells(j, 3).Value
result(x1, 3) = .Cells(j, 27).Value
result(x1, 4) = .Cells(j, 41).Value
End If
Next
End With
.Close SaveChanges:=False
End With
With Workbooks.Add
With Worksheets(1)
.Name = "ExistCells"
.Range("A1:D1").Resize(x1).Value = Results
End With
End With
Application.ScreenUpdating = True
End Sub
Following on from your last point, could you not just exit the loop when the If condition is met? 从最后一点开始,是否可以仅在满足If条件时退出循环? Something like this for example?
例如这样的事情?
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1).Value Then
Target.Sheets(1).Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48).Value
Target.Sheets(1).Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3).Value
Target.Sheets(1).Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27).Value
Target.Sheets(1).Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41).Value
w = w + 1
GoTo ExitLoop
End If
Next j
ExitLoop:
The code could be cleaned up a bit...plus you were closing "Source1.xlsx" twice...and tried to refer to Source1 as a variable even though it was never declared. 可以对代码进行一些清理……加上您两次关闭“ Source1.xlsx”……并尝试将Source1称为变量,即使从未声明过也是如此。 Using
Option Explicit
at the top of the module will allow you find that type of issue easily. 使用模块顶部的
Option Explicit
,您可以轻松找到该类型的问题。 I put in a similar break in the inner For loop like Wilson88 as well. 我在内部For循环中也设置了类似的中断,例如Wilson88。
By using your variables and With
you should be able to speed it up some over ActiveWorkbook
and ActiveSheet
... 通过使用您的变量和
With
您应该能够通过ActiveWorkbook
和ActiveSheet
加快速度...
Sub Loop_Cells()
Dim Source As Workbook, Source2 As Workbook, Target As Workbook
Dim w As Integer, x As Integer, y As Integer
Dim lRow As Long, lRow2 As Long
Dim c As Range
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Application.SheetsInNewWorkbook = 1
Set Source = Workbooks.Open("C:\Reports\Source1.xlsx")
With Source
x = .UsedRange.Columns.Count
.Cells(1, x + 1) = "Concate"
lRow = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow
.Cells(i, x + 1) = .Cells(i, 6). & .Cells(i, 7)
Next i
.Columns(x + 1).NumberFormat = "0"
End With
Set Source2 = Workbooks.Open("C:\Reports\Source2.xlsx")
With Source2
y = .UsedRange.Columns.Count
.Cells(1, y + 1) = "Concate"
lRow2 = .Range("A" & Rows.Count).End(xlUp).Row
For i = 2 To lRow2
.Cells(i, y + 1). = .Cells(i, 48) & .Cells(i, 3)
Next i
.Columns(y + 1).NumberFormat = "0"
End With
Set Target = Workbooks.Add
With Target.Sheets(1)
.Name = "ExistCells"
w = 1
For Each c In Source.Sheets(1).UsedRange.Columns(x + 1).Cells
For j = 2 To lRow2
If c.Value = Source2.Sheets(1).Cells(j, y + 1) Then
.Cells(w, 1).Value = Source2.Sheets(1).Cells(j, 48)
.Cells(w, 2).Value = Source2.Sheets(1).Cells(j, 3)
.Cells(w, 3).Value = Source2.Sheets(1).Cells(j, 27)
.Cells(w, 4).Value = Source2.Sheets(1).Cells(j, 41)
w = w + 1
Exit For
End If
Next j
Next c
End With
Source.Close SaveChanges:=False
Source2.Close SaveChanges:=False
Target.SaveAs FileName:= "C:\Reports\Target.xlsx", _
FileFormat:=xlOpenXMLWorkbook, CreateBackup:=False
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.