Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使VBA循环(对于每个单元格,复制粘贴)更快?_Vba_Excel - Fatal编程技术网

如何使VBA循环(对于每个单元格,复制粘贴)更快?

如何使VBA循环(对于每个单元格,复制粘贴)更快?,vba,excel,Vba,Excel,我有一段代码占用了大量的实际运行时间。似乎这个循环实际上有时会使Excel无响应(对此不是100%确定,但在我看来,这是我在代码中遇到的最可能的罪魁祸首)。无论如何,我想优化这段代码,这样就不会花那么长时间 一些背景: 编辑:application.ScreenUpdate设置为false 表(1)=原始数据 表(2)=面积表 进入循环前j=2 rng是范围,包括表1列CJ中的所有值减去标题 在sheet1列中,CJ是我要循环浏览的组件名称列表。对于每个ComponentName,我要过滤列AL

我有一段代码占用了大量的实际运行时间。似乎这个循环实际上有时会使Excel无响应(对此不是100%确定,但在我看来,这是我在代码中遇到的最可能的罪魁祸首)。无论如何,我想优化这段代码,这样就不会花那么长时间

一些背景:

编辑:application.ScreenUpdate设置为false
表(1)=原始数据
表(2)=面积表
进入循环前j=2
rng是范围,包括表1列CJ中的所有值减去标题

在sheet1列中,CJ是我要循环浏览的组件名称列表。对于每个ComponentName,我要过滤列AL并将列AL中的所有可见值(始终至少有>1个值)复制粘贴(转置)到工作表(2)。

每个组件名通常有大约1000-1200个组件名和10-240个值(与我复制粘贴到sheet2的值相同)。

For Each cell In rng
    ComponentName = cell.Value
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=ComponentName
    RawData.Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1
Next cell

我可以对此循环进行哪些更改以更快地完成流程?

构建一个
ComponentName
值数组,并过滤和复制/粘贴一次,而不是一千次

Dim v As Long, vCOMPNAMEs As Variant

With rng
    ReDim vCOMPNAMEs(.Count)
    For v = LBound(vCOMPNAMEs) To UBound(vCOMPNAMEs)
        vCOMPNAMEs(v) = rng.cells(v + 1).Value2
    Next v
End With

With RawData
    .Range("A:CJ").AutoFilter Field:=17, Criteria1:=vCOMPNAMEs, Operator:=xlFilterValues
    .Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1   '<~~?????
End With
Dim v为长,vCOMPNAMEs为变体
带rng
重拨vCOMPNAMEs(.Count)
对于v=LBound(vCOMPNAMEs)到UBound(vCOMPNAMEs)
vCOMPNAMEs(v)=随机单元格(v+1)。值2
下一个v
以
用原始数据
.Range(“A:CJ”)。自动筛选字段:=17,准则1:=vCOMPNAMEs,运算符:=xlFilterValues
.Range(“AL2”,Range(“AL2”).End(xlDown)).Cells.SpecialCells(xlCellTypeVisible)。复制
AreaTable.Range(“B”和j).Paste特殊转置:=真

j=j+1'构建一个包含
ComponentName
值的数组,并过滤和复制/粘贴一次,而不是一千次

Dim v As Long, vCOMPNAMEs As Variant

With rng
    ReDim vCOMPNAMEs(.Count)
    For v = LBound(vCOMPNAMEs) To UBound(vCOMPNAMEs)
        vCOMPNAMEs(v) = rng.cells(v + 1).Value2
    Next v
End With

With RawData
    .Range("A:CJ").AutoFilter Field:=17, Criteria1:=vCOMPNAMEs, Operator:=xlFilterValues
    .Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1   '<~~?????
End With
Dim v为长,vCOMPNAMEs为变体
带rng
重拨vCOMPNAMEs(.Count)
对于v=LBound(vCOMPNAMEs)到UBound(vCOMPNAMEs)
vCOMPNAMEs(v)=随机单元格(v+1)。值2
下一个v
以
用原始数据
.Range(“A:CJ”)。自动筛选字段:=17,准则1:=vCOMPNAMEs,运算符:=xlFilterValues
.Range(“AL2”,Range(“AL2”).End(xlDown)).Cells.SpecialCells(xlCellTypeVisible)。复制
AreaTable.Range(“B”和j).Paste特殊转置:=真

j=j+1'在运行此操作之前关闭计算,因为每次筛选时,它都会重新计算工作簿,如果有很多公式,则会消耗处理器:

Application.Calculation = xlCalculationManual
For Each cell In Rng
    ComponentName = cell.Value
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=ComponentName
    RawData.Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1
Next cell
Application.Calculation = xlCalculationAutomatic

运行此操作之前请关闭计算,因为每次筛选时,它都会重新计算工作簿,如果有大量公式,则会消耗处理器:

Application.Calculation = xlCalculationManual
For Each cell In Rng
    ComponentName = cell.Value
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=ComponentName
    RawData.Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1
Next cell
Application.Calculation = xlCalculationAutomatic

大卫的建议是我将要发布的,这将非常有帮助。另外,请尝试此操作(不指定ComponentName)。未经测试,但应有效:

For Each cell In rng
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=cell.Value
    RawData.Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1
Next cell
它还可以更快地存储到阵列中。。。不幸的是我不知道你在复制多少个细胞。。。但我假设您在本例中复制2个单元格,根据您的需要进行更改。无论如何,您可以将结果存储到一个数组中,然后一次吐出所有结果,如下所示:

dim arr(300000,1)
For Each cell In rng
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=cell.Value
    arr(j,0) = RawData.Range("AL2")
    arr(j,1) = RawData.Range("AL2").offset(1,0)
    ' etc.... do this for each (or create a loop to capture everything)
    j = j + 1
Next cell

for j_ctr = 1 to j
    AreaTable.Range("B" & j).value=arr(j_ctr,0)
    AreaTable.Range("B" & j+1).value=arr(j_ctr,1)
next

除非昂贵的部分是自动过滤。。。有什么办法可以避免这种情况吗?

大卫的建议就是我要发布的,这将非常有帮助。另外,请尝试此操作(不指定ComponentName)。未经测试,但应有效:

For Each cell In rng
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=cell.Value
    RawData.Range("AL2", Range("AL2").End(xlDown)).Cells.SpecialCells(xlCellTypeVisible).Copy
    AreaTable.Range("B" & j).PasteSpecial Transpose:=True
    j = j + 1
Next cell
它还可以更快地存储到阵列中。。。不幸的是我不知道你在复制多少个细胞。。。但我假设您在本例中复制2个单元格,根据您的需要进行更改。无论如何,您可以将结果存储到一个数组中,然后一次吐出所有结果,如下所示:

dim arr(300000,1)
For Each cell In rng
    RawData.Range("A:CJ").AutoFilter field:=17, Criteria1:=cell.Value
    arr(j,0) = RawData.Range("AL2")
    arr(j,1) = RawData.Range("AL2").offset(1,0)
    ' etc.... do this for each (or create a loop to capture everything)
    j = j + 1
Next cell

for j_ctr = 1 to j
    AreaTable.Range("B" & j).value=arr(j_ctr,0)
    AreaTable.Range("B" & j+1).value=arr(j_ctr,1)
next

除非昂贵的部分是自动过滤。。。有什么办法可以避免这种情况吗?

您可以尝试以下方法:

Dim outputVal As Variant, chkRng As Variant, valRng As Variant
Dim i As Long, j As Long, k As Long
With rawdata
  k = .Cells(Rows.Count, 38).End(xlUp).Row
  chkRng = .Range("Q2:Q" & k).Value
  valRng = .Range("AL2:AL" & k).Value
  ReDim outputVal(rng.Count, 0)

  For Each cell In rng.Value
    k = 0
    For i = LBound(chkRng) To UBound(chkRng)
      If chkRng(i, 1) = cell Then
        outputVal(j, k) = valRng(i, 1)
        k = k + 1
        If k > UBound(outputVal, 2) Then ReDim Preserve outputVal(rng.Count, k)
      End If
    Next
    j = j + 1
  Next
End With
With areatable: .Range(.Cells(1, 2), .Cells(rng.Count + 1, UBound(outputVal, 2) + 2)).Value = outputVal: End With
请用一份副本测试一下。。。没有真正的工作簿可能会把一切都搞砸。。。但它可能会以一个错误结束

请尝试一下,然后告诉我出了什么问题:)

编辑
用一个小表格测试了它,它工作得很好(而且速度也很快),但是:如果没有一个小示例工作簿,很难检查它是否也适用于您

EDIT2

工作方式:当寻找速度时,你需要知道一张纸需要做的每件事都很慢。因此,第一部分简单地获取所有值以检查/复制任何内容,并将它们放入变量中(这在读/写方面要快得多)。(
chkRng
valRng

然后我为输出生成一个变量(
outputVal

知道只有1个值要检查(筛选),我还可以将该列与您的
单元格进行比较。每次它找到匹配项时,另一个值(相同的位置)就会被放入输出值中(并根据需要调整值的大小)

最后,它一步将输出值粘贴到所需范围内

主要缺点:
-不会复制任何格式(仅复制值,但也可以更改为复制公式,而此处无需复制)

-您需要知道准确的范围(到小,值将丢失/到大,并且变量范围之外的每个单元格中都会出现错误代码)

您可以尝试以下方法:

Dim outputVal As Variant, chkRng As Variant, valRng As Variant
Dim i As Long, j As Long, k As Long
With rawdata
  k = .Cells(Rows.Count, 38).End(xlUp).Row
  chkRng = .Range("Q2:Q" & k).Value
  valRng = .Range("AL2:AL" & k).Value
  ReDim outputVal(rng.Count, 0)

  For Each cell In rng.Value
    k = 0
    For i = LBound(chkRng) To UBound(chkRng)
      If chkRng(i, 1) = cell Then
        outputVal(j, k) = valRng(i, 1)
        k = k + 1
        If k > UBound(outputVal, 2) Then ReDim Preserve outputVal(rng.Count, k)
      End If
    Next
    j = j + 1
  Next
End With
With areatable: .Range(.Cells(1, 2), .Cells(rng.Count + 1, UBound(outputVal, 2) + 2)).Value = outputVal: End With
请用一份副本测试一下。。。没有真正的工作簿可能会把一切都搞砸。。。但它可能会以一个错误结束

请尝试一下,然后告诉我出了什么问题:)

编辑
用一个小表格测试了它,它工作得很好(而且速度也很快),但是:如果没有一个小示例工作簿,很难检查它是否也适用于您

EDIT2

工作方式:当寻找速度时,你需要知道一张纸需要做的每件事都很慢。因此,第一部分简单地获取所有值以检查/复制任何内容,并将它们放入变量中(这在读/写方面要快得多)。(
chkRng
valRng

然后我为输出生成一个变量(
outpu)