【发布时间】:2022-01-14 11:30:20
【问题描述】:
作为对我之前的问题的补充,我得到了答复,并且帮助我在超快的时间内完成了项目,我现在有一个类似的项目,原始代码已经可以运行并且运行良好,但是,我有两列,其中包含以下内容:
K 列 - ws 和服务器的名称及其 IP 地址以逗号分隔 L 列 - 只是 IP 地址
在每批名称和 IP 或只是 IP 中,由于各种原因,我对出现在最终输出中的范围不感兴趣。
很遗憾,我无法给出字符串的真实示例,但以下是您可能会发现的示例:
K - Mike [10.6.3.4], Mike1 [10.2.3.4], Mike3 [10.165.75.3]....... L - 10.6.3.4、10.2.3.4、10.165.75.3…………
L中的IP与K中的IP相同,但顺序不一定相同。
这没关系。
我编写了以下子代码,它遍历 excel ws 中的所有行,读取字符串,然后写出相同的字符串,但没有我不想要的范围(你会看到那些是 10.6 和 192.168。
如您所见,我为一行中的第一个字符串编写了一个循环,然后根据列为同一行中的第二个字符串编写了第二个循环,我清除了训练逗号(我不知道如何设置将保存“干净”字符串的新数组的结束长度,所以我得到一些我必须清理的额外逗号)然后我转到下一行直到结束。
效果很好。
我只是觉得它可以做得更快,更清洁,以及一个循环而不是两个循环,以及可能不需要清理额外的逗号。
感谢任何人可能拥有的任何 cmets 或修复程序。
同样,它工作正常,但如果你明白我的意思,它会感觉“不干净”。
'Sub to remove unwanted IP ranges from both columns
Sub CleanNamesIPsfromList()
Const Col_Names = "J"
Const Col_IPs = "K"
Const ROW_NamesIPs = 5 'First line of Names and IP's
Dim wb As Workbook
Dim wsMain As Worksheet
Dim arHoldNames() As String, arHoldIPs() As String
Dim arPutNames() As String, arPutIPs() As String
Dim strHoldNames As String, strHoldIPs As String
Dim txt106 As String, txt192168 As String
Dim rn As Long, rhn As Long, ri As Long, rhi As Long, lastrowN As Long, lastrowI As Long, i As Long
txt106 = "10.6."
txt192168 = "192.168."
Set wb = ActiveWorkbook
With wb
Set wsMain = .Sheets("Main")
End With
With wsMain
lastrowN = .Cells(.Rows.Count, Col_Names).End(xlUp).Row
lastrowI = .Cells(.Rows.Count, Col_IPs).End(xlUp).Row
If lastrowN < ROW_NamesIPs Or lastrowI < ROW_NamesIPs Then
MsgBox "No text found in Columns " & Col_Names & " " & Col_IPs, vbCritical
Exit Sub
End If
'Run through whole ws row by row in both columns
For i = ROW_NamesIPs To lastrowN
rhn = 0
'Load list of names into string holder
strHoldNames = .Cells(i, Col_Names).Value
'Split the string into the holding array based on the comma
arHoldNames = Split(strHoldNames, ",")
'Loop through the array to find those names not containg unwanted data
ReDim arPutNames(0 To UBound(arHoldNames))
For rn = 0 To UBound(arHoldNames)
If InStr(1, arHoldNames(rn), txt106, vbTextCompare) > 0 Or InStr(1, arHoldNames(rn), txt192168, vbTextCompare) > 0 Then
'If it contains unwanted string, increment rn to next array cell and move on
rn = rn + 1
Else
'I want this string so put in new array holder and increment array counter
arPutNames(rhn) = arHoldNames(rn)
rhn = rhn + 1
End If
Next 'Loop through array holding origional string
'I have what I want, so put it back in relevant cell in ws
.Cells(i, Col_Names).Value = Join(arPutNames, ",")
'Remove all trailing commas
While Right(.Cells(i, Col_Names).Value, 1) = ","
.Cells(i, Col_Names).Value = Left(.Cells(i, Col_Names).Value, Len(.Cells(i, Col_Names).Value) - 1)
Wend
rhi = 0
'Load list of names into string holder
strHoldIPs = .Cells(i, Col_IPs).Value
'Split the string into the holding array based on the comma
arHoldIPs = Split(strHoldIPs, ",")
'Loop through the array to find those names not containg unwanted data
ReDim arPutIPs(0 To UBound(arHoldIPs))
For ri = 0 To UBound(arHoldIPs)
If InStr(1, arHoldIPs(ri), txt106, vbTextCompare) > 0 Or InStr(1, arHoldIPs(ri), txt192168, vbTextCompare) > 0 Then
'If it contains unwanted string, increment ri to next array cell and move on
ri = ri + 1
Else
'I want this string so put in new array holder and increment array counter
arPutIPs(rhi) = arHoldIPs(ri)
rhi = rhi + 1
End If
Next 'Loop through array holding origional string
'I have what I want, so put it back in relevant cell in ws
.Cells(i, Col_IPs).Value = Join(arPutIPs, ",")
'Remove all trailing commas
While Right(.Cells(i, Col_IPs).Value, 1) = ","
.Cells(i, Col_IPs).Value = Left(.Cells(i, Col_IPs).Value, Len(.Cells(i, Col_IPs).Value) - 1)
Wend
Next 'Move to next row and repeat untill end
End With 'End main
End Sub
新代码
好的,基于将所有数据读入数组,我写了这段代码(当然是借用betters的)。
Dim Lastcell As Range
Set LastCell = .Range("K5:L5").End(xlDown)
'capture all of the data at once with a range-array copy
Dim arHoldAllNames As String, ArHoldAllIPs As String
arHoldAllNames = .Range("K5", LastCell).Value
ArHoldAllIPs = .Range("L5", LastCell).Value
for i = 0 to UBound(arHoldAllNames, 1)
'Code for Names
Next
for i = 0 to UBound(ArHoldAllIPs, 1)
'Code for IPs
Next
temp = 0
For i = 5 To LastCell
.Cells(i, Col_Names).Value = arHoldAllNames(temp)
.Cells(i, Col_IPs).Value = ArHoldAllIPs(temp)
i = i + 1
temp = temp + 1
Next
这就是你们的意思吗?
另外,我发现我可以将一系列数据读入一个数组,这无疑加快了速度。
那就是这段代码:
arHoldAllNames = .Range("K5", LastCell).Value
arHoldAllIPs = .Range("L5", LastCell).Value
然后我可以反过来做吗:
.Range("K5", LastCell).Value = arHoldAllNames
.Range("L5", LastCell).Value = arHoldAllIPs
并让 ws 中的所有单元格与数组中的内容一起传播?
还是我还需要做 For 循环:
temp = 0
For i = 5 To LastCell
.Cells(i, Col_Names).Value = arHoldAllNames(temp)
.Cells(i, Col_IPs).Value = ArHoldAllIPs(temp)
i = i + 1
temp = temp + 1
Next
【问题讨论】:
-
一个很大的改进是将工作表中的所有值放入一个数组中,在数组中进行所有更改,然后将数组放回工作表中。我已经看到我的项目的运行时间因该更改而减少了 90%。
-
我的工作表可以有 7000 到 20000 行。并不是说数组无法容纳它。所以你是说,将两列中的所有数据读入两个单独的数组,然后对这些数组而不是 ws 进行工作?
-
具体来说,使用范围数组复制。见这里stackoverflow.com/questions/19164840/…。如
dim data as variant: data = Range("A1:D10000"): data(r,c) = ... : Range("A1:D10000") = data。因此,将所有值(您需要的)一次复制到一个变量数组中,更改数组中的值,然后将它们一次全部复制回电子表格单元格。它快得多.. -
这个 (stackoverflow.com/questions/68130319/…) 可能更容易阅读。具体看前几行和最后几行代码。
-
好的,我看到您实际上已经回答了所有问题@RBarryYoung,并且还对代码进行了更改。我稍后会试一试,如果成功了,我会告诉你的:)