VBA:用于交叉工作表操作的速度非常慢的宏(7k行需要15分钟!)
我有一个excel文件,有两张表格,分别是:<代码>材料表和VBA:用于交叉工作表操作的速度非常慢的宏(7k行需要15分钟!),vba,excel,Vba,Excel,我有一个excel文件,有两张表格,分别是:材料表和结果表,其中后者是结果的空表。在物料表中我有物料信息和移动代码。至于模式: 列A有物料代码,列G有移动代码 现在,对于每种材料,可能有多行具有不同于移动代码集(101102201202241242261262561)的移动代码。我需要检查并应用以下逻辑: 从材料表复制材料的所有行并粘贴 结果表“”, 如果(此材料的202计数>=此材料的201计数)和(此材料的242计数>=此材料的241计数)和(此材料的262计数>=此材料的261计数) 目前
结果表
,其中后者是结果的空表。在物料表中
我有物料信息和移动代码。至于模式:
列A有物料代码,列G有移动代码
现在,对于每种材料,可能有多行具有不同于移动代码集(101102201202241242261262561)的移动代码。我需要检查并应用以下逻辑:
从材料表
复制材料的所有行并粘贴
结果表“”,如果(此材料的202计数>=此材料的201计数)和(此材料的242计数>=此材料的241计数)和(此材料的262计数>=此材料的261计数) 目前,我有以下代码(文章末尾)。在此过程中,它过滤有效的物料代码并将这些代码存储在结果表中(还不是整行!) 我想要的是:
Sub FilterWRTMovement()
Application.ScreenUpdating = False
Dim collectionUniqueMaterials() As String
Dim LRow As Long, counter1 As Long, counter2 As Long
Dim result(10000) As String, movementOfOneMaterial() As String, current As String
Dim has202 As Boolean, has242 As Boolean, has262 As Boolean
Dim Destination As Worksheet
LRow = Cells(Rows.Count, 1).End(xlUp).Offset(0, 0).Row
c = collectUniqueMaterials(collectionUniqueMaterials, LRow)
counter1 = 0
counter2 = 0
Set Destination = Worksheets("Resultant Sheet")
With ActiveWorkbook.Worksheets("Material Sheet").Range("A2:A" & LRow)
.EntireRow.Hidden = False
For Each i In collectionUniqueMaterials
i = Trim(i)
ReDim movementOfOneMaterial(200) As String
has202 = True
has242 = True
has262 = True
counter1 = 0
For j = 1 To .Rows.Count
current = Trim(Cells(j, 1))
If current = i Then
movementOfOneMaterial(counter1) = Cells(j, 7)
counter1 = counter1 + 1
End If
Next j
FilterValues movementOfOneMaterial, has202, has242, has262
If has202 = True And has242 = True And has262 = True Then
result(counter2) = i
counter2 = counter2 + 1
End If
Erase movementOfOneMaterial
Next i
End With
Destination.Range("A1").Resize(10000, 1).Value = Application.Transpose(result)
'For Each tup In result
'FindMe (tup)
'Next tup
End Sub
Function collectUniqueMaterials(ByRef collection() As String, ByRef last As Long)
Dim tmp As String
myselect = ActiveWorkbook.Worksheets("Material Sheet").Range("A2:A" & last)
For Each cell In myselect
If (cell <> "") And (InStr(tmp, cell) = 0) Then
tmp = tmp & cell & "|"
End If
Next cell
If Len(tmp) > 0 Then tmp = Left(tmp, Len(tmp) - 1)
collection = Split(tmp, "|")
End Function
Function FilterValues(ByRef sarrCodes() As String, ByRef has202 As Boolean, ByRef has242 As Boolean, ByRef has262 As Boolean)
Dim a As Long
Dim vKey As Variant
Dim objDic As Object
Set objDic = CreateObject("Scripting.Dictionary")
For a = LBound(sarrCodes) To UBound(sarrCodes)
If objDic.Exists(sarrCodes(a)) Then
objDic.Item(sarrCodes(a)) = objDic.Item(sarrCodes(a)) + 1
Else
objDic.Add sarrCodes(a), 1
End If
Next a
If objDic.Exists("201") And objDic.Item("201") <> "" Then
has202 = False
If objDic.Exists("202") And objDic.Item("202") <> "" And objDic.Item("202") >= objDic.Item("201") Then
has202 = True
End If
ElseIf objDic.Exists("241") And objDic.Item("241") <> "" Then
has242 = False
If objDic.Exists("242") And objDic.Item("242") <> "" And objDic.Item("242") >= objDic.Item("241") Then
has242 = True
End If
ElseIf objDic.Exists("261") And objDic.Item("261") <> "" Then
has262 = False
If objDic.Exists("262") And objDic.Item("262") <> "" And objDic.Item("262") >= objDic.Item("261") Then
has262 = True
End If
End If
End Function
现在,不是将唯一的物料代码保存在结果表中(Destination.Range(“A1”).Resize(10000,1).Value=Application.Transpose(result)
),而是根据result
数组的每个值从“物料集”复制所有行的优化方法是什么(给定:对于结果元素的每个值,物料表中有多行。我希望所有行都得到过滤后的数据)
更新
在Tim的帖子中稍加调整,我就能在一秒钟内达到预期效果。以下是VBA脚本:
Sub FilterMaterialWRTMovement()
Const SourceSheet As String = "Material Sheet"
Const DestinationSheet As String = "Resultant Sheet"
Const COL_ID As Integer = 1
Const COL_MOVE As Integer = 7
Dim dict As Object
Dim data As Variant, data2(), numRows As Long, numCols As Long
Dim r As Long, c As Long
Dim shtSrc As Worksheet, shtDest As Worksheet
Dim id, mv, arrMv, pos, tmp
Dim data2Row As Long
Dim firstPass As Boolean
Set dict = CreateObject("Scripting.Dictionary")
'movement codes to count
arrMv = Array(201, 202, 241, 242, 261, 262)
Set shtSrc = ActiveWorkbook.Sheets(SourceSheet)
Set shtDest = ActiveWorkbook.Sheets(DestinationSheet)
shtDest.Cells.Clear
data = shtSrc.Range(shtSrc.Range("A2"), _
shtSrc.Cells(Rows.Count, 1).End(xlUp).Offset(0, 10)).Value
numRows = UBound(data, 1)
numCols = UBound(data, 2)
ReDim data2(1 To numRows, 1 To numCols)
data2Row = 1
firstPass = True
runAgain:
For r = 1 To numRows
id = data(r, COL_ID)
If firstPass Then
'collecting counts...
mv = data(r, COL_MOVE)
If Not dict.Exists(id) Then dict.Add id, Array(0, 0, 0, 0, 0, 0)
pos = Application.Match(mv, arrMv, 0)
If Not IsError(pos) Then
tmp = dict(id)
If id = 7024113 Then
cwe = 1
End If
tmp(pos - 1) = tmp(pos - 1) + 1
dict(id) = tmp
End If
'firstPass = False
Else
'copying rows
tmp = dict(id)
If (tmp(0) <> 0) Or (tmp(2) <> 0) Or (tmp(4) <> 0) Then
If Not ((tmp(0) <> 0 And tmp(1) < tmp(0)) Or (tmp(2) <> 0 And tmp(3) < tmp(2)) Or (tmp(4) <> 0 And tmp(5) < tmp(4))) Then
For c = 1 To numCols
data2(data2Row, c) = data(r, c)
Next c
data2Row = data2Row + 1
End If
End If
End If
Next r
If firstPass Then
Beep
firstPass = False
GoTo runAgain
Else
shtDest.Cells(2, 1).Resize(numRows, numCols).Value = data2
End If
End Sub
子过滤器材料移动()
Const SourceSheet As String=“物料表”
Const DestinationSheet As String=“结果表”
常量列ID为整数=1
常量COL_移动为整数=7
作为对象的Dim dict
Dim数据作为变量,data2(),numRows作为长,numCols作为长
变暗r为长,c为长
尺寸shtSrc作为工作表,shtDest作为工作表
仪表板id、mv、arrMv、pos、tmp
变暗数据2尽可能长
Dim firstPass作为布尔值
Set dict=CreateObject(“Scripting.Dictionary”)
'要计数的移动代码
arrMv=阵列(20120224124261262)
设置shtSrc=ActiveWorkbook.Sheets(SourceSheet)
Set shtDest=ActiveWorkbook.Sheets(目的表)
shtDest.Cells.Clear
数据=shtSrc.范围(shtSrc.范围(“A2”)_
shtSrc.Cells(Rows.Count,1).End(xlUp).Offset(0,10)).Value
numRows=UBound(数据,1)
numCols=UBound(数据,2)
ReDim数据2(1到numRows,1到numCols)
data2Row=1
firstPass=True
再次运行:
对于r=1到numRows
id=数据(r,COL\u id)
如果第一次通过的话
“收集计数。。。
mv=数据(r,COL_移动)
如果不存在dict.Exists(id),则dict.Add id,数组(0,0,0,0,0)
位置=应用程序匹配(mv、arrMv、0)
如果不是IsError(pos),则
tmp=dict(id)
如果id=7024113,则
cwe=1
如果结束
tmp(位置1)=tmp(位置1)+1
dict(id)=tmp
如果结束
'firstPass=False
其他的
'复制行
tmp=dict(id)
如果(tmp(0)0)或(tmp(2)0)或(tmp(4)0),则
如果不是((tmp(0)0和tmp(1)
谢谢大家!这是哪个版本的Excel?如果是2007年或2010年,罪魁祸首可能是j=1到.Rows.Count的
,处理大量不必要的单元格。
您可以尝试使用
范围内的每个c(“a:a”)。特殊单元格(xlCellTypeConstants)
相反。它是哪个版本的Excel?如果是2007或2010,罪魁祸首可能是j=1到.Rows.Count的,处理大量不必要的单元格。
您可以尝试使用
范围内的每个c(“a:a”)。特殊单元格(xlCellTypeConstants)
相反。两个观察结果:
(正如iDevelop提到的那样,.Rows.Count会增加很多不必要的开销。另外,LRow不是已经设置为最后一个行号了吗
另外,如果我正确地阅读了代码,您将值添加到数组中,然后在FilterValues子项中对它们进行计数。难道不可能将它们添加到字典中,并在一次传递中递增它们,而不是使用嵌套循环并调用FilterValues吗?两个观察结果:
(正如iDevelop提到的那样,.Rows.Count会增加很多不必要的开销。另外,LRow不是已经设置为最后一个行号了吗
另外,如果我正确地读取了代码,那么就是将值添加到数组中,然后在FilterVa中对它们进行计数
Sub FilterMaterialWRTMovement()
Const SourceSheet As String = "Material Sheet"
Const DestinationSheet As String = "Resultant Sheet"
Const COL_ID As Integer = 1
Const COL_MOVE As Integer = 7
Dim dict As Object
Dim data As Variant, data2(), numRows As Long, numCols As Long
Dim r As Long, c As Long
Dim shtSrc As Worksheet, shtDest As Worksheet
Dim id, mv, arrMv, pos, tmp
Dim data2Row As Long
Dim firstPass As Boolean
Set dict = CreateObject("Scripting.Dictionary")
'movement codes to count
arrMv = Array(201, 202, 241, 242, 261, 262)
Set shtSrc = ActiveWorkbook.Sheets(SourceSheet)
Set shtDest = ActiveWorkbook.Sheets(DestinationSheet)
shtDest.Cells.Clear
data = shtSrc.Range(shtSrc.Range("A2"), _
shtSrc.Cells(Rows.Count, 1).End(xlUp).Offset(0, 10)).Value
numRows = UBound(data, 1)
numCols = UBound(data, 2)
ReDim data2(1 To numRows, 1 To numCols)
data2Row = 1
firstPass = True
runAgain:
For r = 1 To numRows
id = data(r, COL_ID)
If firstPass Then
'collecting counts...
mv = data(r, COL_MOVE)
If Not dict.Exists(id) Then dict.Add id, Array(0, 0, 0, 0, 0, 0)
pos = Application.Match(mv, arrMv, 0)
If Not IsError(pos) Then
tmp = dict(id)
If id = 7024113 Then
cwe = 1
End If
tmp(pos - 1) = tmp(pos - 1) + 1
dict(id) = tmp
End If
'firstPass = False
Else
'copying rows
tmp = dict(id)
If (tmp(0) <> 0) Or (tmp(2) <> 0) Or (tmp(4) <> 0) Then
If Not ((tmp(0) <> 0 And tmp(1) < tmp(0)) Or (tmp(2) <> 0 And tmp(3) < tmp(2)) Or (tmp(4) <> 0 And tmp(5) < tmp(4))) Then
For c = 1 To numCols
data2(data2Row, c) = data(r, c)
Next c
data2Row = data2Row + 1
End If
End If
End If
Next r
If firstPass Then
Beep
firstPass = False
GoTo runAgain
Else
shtDest.Cells(2, 1).Resize(numRows, numCols).Value = data2
End If
End Sub
Sub FilterAndCopyRows()
Const COL_ID As Integer = 1
Const COL_MOVE As Integer = 7
Dim dict As New Scripting.dictionary
Dim data As Variant, data2(), numRows As Long, numCols As Long
Dim r As Long, c As Long
Dim shtSrc As Worksheet, shtDest As Worksheet
Dim id, mv, arrMv, pos, tmp
Dim data2Row As Long
Dim firstPass As Boolean
'movement codes to count
arrMv = Array(201, 202, 241, 242, 261, 262)
Set shtSrc = ActiveWorkbook.Sheets("Material Sheet")
Set shtDest = ActiveWorkbook.Sheets("Resultant Sheet")
data = shtSrc.Range(shtSrc.Range("A2"), _
shtSrc.Cells(Rows.Count, 1).End(xlUp).Offset(0, 6)).Value
numRows = UBound(data, 1)
numCols = UBound(data, 2)
ReDim data2(1 To numRows, 1 To 7)
data2Row = 1
firstPass = True
runAgain:
For r = 1 To numRows
id = data(r, COL_ID)
If firstPass Then
'collecting counts...
mv = data(r, COL_MOVE)
If Not dict.Exists(id) Then dict.Add id, Array(0, 0, 0, 0, 0, 0)
pos = Application.Match(mv, arrMv)
If Not IsError(pos) Then
tmp = dict(id)
tmp(pos - 1) = tmp(pos - 1) + 1
dict(id) = tmp
End If
Else
'copying rows
tmp = dict(id)
If (tmp(1) > tmp(0)) And (tmp(3) > tmp(2)) And (tmp(5) > tmp(4)) Then
For c = 1 To numCols
data2(data2Row, c) = data(r, c)
Next c
data2Row = data2Row + 1
End If
End If
Next r
If firstPass Then
Beep
firstPass = False
GoTo runAgain
Else
shtDest.Cells(2, 1).Resize(numRows, numCols).Value = data2
End If
End Sub
Application.Calculation = xlCalculationManual 'turn off the automatic calc
'your code goes here
Application.Calculation = xlCalculationAutomatic 'turn On the automatic calc
if a = "" or a = "" 'thats not good way to do