【发布时间】:2018-03-15 06:24:36
【问题描述】:
我有一个包含 10 多张工作表的工作簿,每张都有数十万个值(125k sheet1、240k sheet 2、400k sheet 3,等等)表。
我无法获取代码来完成第一张纸上的数据修剪。代码已经运行了一个多小时而没有完成第一张工作表。我也尝试过使用较小的数据集(5 张纸中约 1000 个点),但宏只能成功修剪第一张纸上的点。其他表没有修改
下面是我用来删除行间隔的代码;这是我能找到的删除行的最可定制的方式(这正是我正在寻找的:定制/简单性
lastRow = Application.ActiveSheet.UsedRange.Rows.Count
For i = 2 To lastRow Step 1 'Interval of rows to delete
Range(Rows(i), Rows(i + 997)).Delete Shift:=xlUp
Next i
这个特定任务的代码被插入到这个问题中找到的代码的修改版本中*感谢最初编写它们的人
问题:Excel VBA Performance - 1 million rows - Delete rows containing a value, in less than 1 min
这是 Paul bica 在他的代码中使用的辅助函数
Public Sub FastWB(Optional ByVal opt As Boolean = True)
With Application
.Calculation = IIf(opt, xlCalculationManual, xlCalculationAutomatic)
.DisplayAlerts = Not opt
.DisplayStatusBar = Not opt
.EnableAnimations = Not opt
.EnableEvents = Not opt
.ScreenUpdating = Not opt
End With
FastWS , opt
End Sub
Public Sub FastWS(Optional ByVal ws As Worksheet = Nothing, _
Optional ByVal opt As Boolean = True)
If ws Is Nothing Then
For Each ws In Application.ActiveWorkbook.Sheets
EnableWS ws, opt
Next
Else
EnableWS ws, opt
End If
End Sub
Private Sub EnableWS(ByVal ws As Worksheet, ByVal opt As Boolean)
With ws
.DisplayPageBreaks = False
.EnableCalculation = Not opt
.EnableFormatConditionsCalculation = Not opt
.EnablePivotTable = Not opt
End With
End Sub
由 marko2049 生成测试集的漂亮小代码:
Sub DevelopTest()
Dim index As Long
FastWB True
ActiveSheet.UsedRange.Clear
For index = 1 To 1000000 '1 million test
ActiveSheet.Cells(index, 1).Value = index
If (index Mod 10) = 0 Then
ActiveSheet.Cells(index, 2).Value = "Test String"
Else
ActiveSheet.Cells(index, 2).Value = "Blah Blah Blah"
End If
Next index
Application.StatusBar = ""
FastWB False
End Sub
生成测试集并将其复制到多个工作表后,我运行了以下代码的修改版本
代码主体由用户marko5049制作
Sub DeleteRowFast()
Dim curWorksheet As Worksheet 'Current worksheet vairable
Dim rangeSelection As Range 'Selected range
Dim startBadVals As Long 'Start of the unwanted values
Dim endBadVals As Long 'End of the unwanted values
Dim strtTime As Double 'Timer variable
Dim lastRow As Long 'Last Row variable
Dim lastColumn As Long 'Last column variable
Dim indexCell As Range 'Index range start
Dim sortRange As Range 'The range which the sort is applied to
Dim currRow As Range 'Current Row index for the for loop
Dim cell As Range 'Current cell for use in the for loop
On Error GoTo Err
Set rangeSelection = Application.InputBox("Select the (N=) range to be checked", "Get Range", Type:=8) 'Get the desired range from the user
Err.Clear
M1 = MsgBox("This is recommended for large files (50,000 or more entries)", vbYesNo, "Enable Fast Workbook?") 'Prompt the user with an option to enable Fast Workbook, roughly 150% performace gains... Recommended for incredibly large files
Select Case M1
Case vbYes
FastWB True 'Enable fast workbook
Case vbNo
FastWB False 'Disable fast workbook
End Select
strtTime = Timer 'Begin the timer
Set curWorksheet = ActiveSheet
lastRow = CLng(rangeSelection.SpecialCells(xlCellTypeLastCell).Row)
lastColumn = curWorksheet.Cells(1, 16384).End(xlToLeft).Column
Set indexCell = curWorksheet.Cells(1, 1)
On Error Resume Next
If rangeSelection.Rows.Count > 1 Then 'Check if there is anything to do
lastVisRow = rangeSelection.Rows.Count
Set sortRange = curWorksheet.Range(indexCell, curWorksheet.Cells(curWorksheet.Rows(lastRow).Row, 16384).End(xlToLeft)) 'Set the sort range
sortRange.Sort Key1:=rangeSelection.Cells(1, 1), Order1:=xlAscending, Header:=xlNo 'Sort by values, lowest to highest
startBadVals = rangeSelection.Find(What:="Test String", LookAt:=xlWhole, MatchCase:=False).Row
endBadVals = rangeSelection.Find(What:="Test String", LookAt:=xlWhole, SearchDirection:=xlPrevious, MatchCase:=False).Row
curWorksheet.Range(curWorksheet.Rows(startBadVals), curWorksheet.Rows(endBadVals)).EntireRow.Delete 'Delete uneeded rows, deleteing in continuous range blocks is quick than seperated or individual deletions.
sortRange.Sort Key1:=indexCell, Order1:=xlAscending, Header:=xlNo 'Sort by index instead of values, lowest to highest
End If
Application.StatusBar = "" 'Reset the status bar
FastWB False 'Disable fast workbook
MsgBox CStr(Round(Timer - strtTime, 2)) & "s" 'Display duration of task
Err:
Exit Sub
End Sub
我将上面的代码修改如下
Sub DeleteRowFastMod()
Dim lastRow As Long
Dim i As Long
Dim ws As Worksheet
Dim wb As Workbook
Set wb = Application.ActiveWorkbook
On Error GoTo Err
'Get the desired range from the user
Err.Clear
FastWB True 'Enable fast workbook
strtTime = Timer 'Begin the timer
On Error Resume Next
For Each ws In wb.Worksheets(1) 'Loop through sheets in workbook
ws.Activate
lastRow = Application.ActiveSheet.UsedRange.Rows.Count
If lastRow > 1 Then 'Check if there is anything to do
For i = 2 To lastRow Step 1 'Interval of rows to delete
Range(Rows(i), Rows(i + 997)).Delete Shift:=xlUp
Next i
End If
Next
Application.StatusBar = "" 'Reset the status bar
FastWB False 'Disable fast workbook
MsgBox CStr(Round(Timer - strtTime, 2)) & "s" 'Display duration of task
Err:
Exit Sub
End Sub
我不确定如何进一步修改此代码以及时在工作簿中的每个工作表上运行。
提前感谢您的任何指导
【问题讨论】:
-
你没有描述你想要做什么。
trimming down the sheets by keeping every thousandth or so point in each sheet.毫无意义 -
无意冒犯,但您不理解您尝试修改的代码。如果您想理解它,我建议您单步执行代码并查看它在做什么。如果您想使用与以前相同的方法,您要做的是制作一个放入原始行号的辅助列,第二个辅助列说明该行是否为 1000 的倍数(如果是,则输入“Y” ),按第二个辅助列排序,删除一个范围的行(在第二个辅助列中带有“N”的行),并使用第一个辅助列来处理数据。
-
另一种选择是简单地创建另一个工作表并使用工作表函数获取每 1000 行,然后删除原始工作表。这可能会比您最初尝试的方法慢一点,但也会相当快。
-
此外,这仅适用于 1 个工作表,因为您使用了
For Each ws In wb.Worksheets(1)行。请注意,wb.Worksheets(1)只是 1 个工作表。您想使用他们在您尝试修改的代码中所做的相同的事情,For Each ws In wb.Sheets