20. september 2006 - 12:27Der er
59 kommentarer og 3 løsninger
Hjælp til at speede VBA-kode op
Hej X'perter!
Nedenstående makro løber gennem en matrix, der typisk omfatter C17 til E5000 og sletter de rækker, hvor tværsummen er 0, fordi cellerne enten er tomme eller lig 0.
Men den er ikke særlig elegant! Især generer denne mig:
i = i - 1 slut = slut - 1 If slut < i Then Exit Sub som altså reducerer løbeparameteren og slutparameteren i en for-next løkke. Endvidere er den ikke særlig hurtig.
Nogen gode forslag? På forhånd tak! §;-D
Hele koden:
Public Sub slet0linier() ' Løber gennem alle rækker i tabellen og sletter de rækker, hvor tværsummen er = 0, fordi de enten er tomme eller indeholder et 0
Dim i As Integer, d As Integer, slut As Integer Dim s As Single
For i = 17 To slut s = (Cells(i, 3) + Cells(i, 4) + Cells(i, 5)) If s = 0 Then Rows(i).EntireRow.Delete Shift:=xlUp i = i - 1 slut = slut - 1 If slut < i Then Exit Sub Else d = d + 1 ' laver intet. Er kun med for Else-strukturens skyld End If Next
slut = Range("C63536").End(xlUp).Row ActiveSheet.PageSetup.PrintArea = "C12:E" & slut
normalt ville jeg lave en For i = slut To 17 Step - 1 så rækkerne gennemløbes bagfra når jeg sletter linier... så vil du slipper for i=i-1 og slut=slut-1
Hvis du har formler i arket der ikke må slettes, kan du gøre således:
Public Sub slet0linier() Dim I As Long slut = Range("C63536").End(xlUp).Row Dim myarr() myarr = Range("C17:E" & slut) For I = 17 To slut Z = myarr(I - 16, 1) + myarr(I - 16, 2) + myarr(I - 16, 3) If myarr(I - 16, 1) + myarr(I - 16, 2) + myarr(I - 16, 3) = 0 Then omraade = omraade & I & ":" & I & "," End If Next omraade = Left(omraade, Len(omraade) - 1) Range(omraade).Select Selection.Delete Shift:=xlUp End Sub
>>> akyhne, efter at have dimmet omraade som range, får jeg nu følgende fejl: "Object variable or With block variable not set" i linien "omraade = omraade & I & ":" & I & ",""
Dim x As Variant Dim r, c, rk rk = Range("C65500").End(xlUp).Row Application.ScreenUpdating = False x = Range("C17:E" & rk) For r = LBound(x, 1) To UBound(x, 1) For c = LBound(x, 2) To UBound(x, 2) If x(r, c) = 0 Then x(r, c) = Empty End If Next Next Range("C17:E" & rk) = x Range("C17:E" & rk).Select On Error GoTo ingen Selection.SpecialCells(xlCellTypeBlanks).Select Selection.EntireRow.Delete ingen: Range("C17").Select Application.ScreenUpdating = True
Sub SletNul() Dim I, rk rk = Range("C65500").End(xlUp).Row Application.ScreenUpdating = False For I = rk To 1 Step -1 If Application.WorksheetFunction.Sum(Range("C" & I & ":E" & I)) = 0 Then Rows(I).EntireRow.Delete Shift:=xlUp End If Next Application.ScreenUpdating = True
måske skal automatisk beregning lige slås fra også
Sub SletNul() Dim I, rk rk = Range("C65500").End(xlUp).Row Application.ScreenUpdating = False Application.Calculation = xlCalculationManual For I = rk To 1 Step -1 If Application.WorksheetFunction.Sum(Range("C" & I & ":E" & I)) = 0 Then Rows(I).EntireRow.Delete Shift:=xlUp End If Next Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True
Sub Makro3() Dim slut As Long slut = Range("C63536").End(xlUp).Row For I = 1 To slut If Application.WorksheetFunction.Sum(Range("C" & I & ":E" & I)) = 0 Then Range("C" & I & ":E" & I).ClearContents End If Next On Error Resume Next Range("E1:E" & slut).SpecialCells(xlCellTypeBlanks).EntireRow.Delete End Sub
>>> kabbak og bak, begge jeres virker, men jeg må nu nok sige, at baks forslag vinder på elegance - og især på hurtighed!
Jeg har ikke kunne få akyhne og excelents forslag til at virke, da jeg enten får kørselsfejl eller også blanker den bare 0-cellerne uden at slette de tomme rækker. Men rigtig mange tak for forsøgene, alle sammen!
Private Sub CommandButton1_Click() Dim I As Long Dim myarr() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual I = 1 Forfra: slut = Range("C63536").End(xlUp).Row myarr = Range("C" & I + poss & ":E" & slut) Z = 0 For I = I To slut If I < slut - poss Then If myarr(I, 1) + myarr(I, 2) + myarr(I, 3) = 0 Then omraade = omraade & I + poss & ":" & I + poss & "," Z = Z + 1 End If End If LL = LL + 1 If Z = 20 Then GoTo slet: Next slet: F = F + 20 poss = LL - F omraade = Left(omraade, Len(omraade) - 1) I = 1 On Error GoTo slut Range(omraade).Select Selection.Delete Shift:=xlUp omraade = "" GoTo Forfra: slut: Range("C1").Select Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = False End Sub
Hold da op, gutter! Det her begynder at blive helt videnskabeligt!
Nu har jeg også siddet med stopuret, en frisk tabel (ca. 50% skal slettes) og genstartet Excel for hvert forsøg. akyhnes er faktisk hurtigst på disse præmisser! Til gengæld mener jeg også, at din kode bruger nogle af de teknikker, jeg helst ville undgå, hvor det bliver svært at overskue, hvad koden egentlig laver.
Der er noget, der ligner dødt løb mellem kabbak og bak, og faktisk en lille smule hurtigere til kabbak, når man tager tid på det!
Og kabbak har faktisk en vigtig pointe! I visse af de rappporter, som laver de tabeller, jeg bruger makroen i, kan det forekomme, at der er værdi i C, men ikke i D og E. Kun at fokusere på tomme celler i E-kolonnen medfører en - omend beskeden - fare for, at jeg kommer til at slette linier med værdier i!
Så her vil jeg nok ændre tildelingen og give pointene til kabbak. Håber, at det er acceptabelt for alle parter. Og ellers galper I bare op! Men nok en gang, tusind tak for indsparkene! Det er sjældent, at man når at lære så meget nyt på en dag!
Enig, først nu gik kabbaks pointe op for mig...sorry, det må skyldes demens lige to spm. er der formler i arket eller eller det bare rå data ? vil en sortering ødelægge noget ?
test lige denne. Bemærk at den indsætter (og sletter) en sorteringskolonne i BB, dette kan ændres
Sub alternativ() Dim i As Long Dim slut As Long Dim t As Long Dim w As Range 'Start timer t = Timer
Application.ScreenUpdating = False
slut = Range("C63536").End(xlUp).Row 'indsæt sorteringskolonne og indsæt formel der giver rækkenummer Range("BB1").FormulaR1C1 = "=ROW()" 'fyld nedad Range("BB1").AutoFill Destination:=Range("BB1:BB" & slut) 'gennemtving en kalkulation ActiveSheet.Calculate 'slå så automatisk kalkulation fra Application.Calculation = xlCalculationManual 'Hvis summen af C,D,og E er 0, så fjern alt indhold i rækken With Application.WorksheetFunction For i = 2 To slut Set w = Range("c" & i & ":E" & i) If .Sum(w) = 0 Then w.EntireRow.Clear Next End With On Error Resume Next 'Sorter nu på den indsatte kolonne med rækkenumre Range("B1:BB" & slut).Sort Key1:=Range("BB1"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _ DataOption1:=xlSortNormal
' Application.Calculation = xlCalculationAutomatic 'Ryd så den indsatte kolonne Range("F:F").Clear 'sæt skærmopdatering og kalkulation til igen Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True 'vis timeren MsgBox Timer - t End Sub
Sub alternativ() Dim i As Long Dim slut As Long Dim t As Long Dim w As Range 'Start timer t = Timer
Application.ScreenUpdating = False 'slå så automatisk kalkulation fra Application.Calculation = xlCalculationManual
slut = Range("C63536").End(xlUp).Row 'indsæt sorteringskolonne og indsæt formel der giver rækkenummer Range("BB1") = "1" 'fyld nedad Range("BB1").DataSeries Rowcol:=xlColumns, Type:=xlLinear, Step:=1, Stop:=slut
'Hvis summen af C,D,og E er 0, så fjern alt indhold i rækken With Application.WorksheetFunction For i = 2 To slut Set w = Range("c" & i & ":E" & i) If .Sum(w) = 0 Then w.EntireRow.Clear Next End With On Error Resume Next 'Sorter nu på den indsatte kolonne med rækkenumre Range("B1:BB" & slut).Sort Key1:=Range("BB1"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _ DataOption1:=xlSortNormal
' Application.Calculation = xlCalculationAutomatic 'Ryd så den indsatte kolonne Range("BB:BB").Clear 'sæt skærmopdatering og kalkulation til igen Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True 'vis timeren MsgBox Timer - t End Sub
Set ud fra spørgsmålet - speed er målet - må man jo nu sige at bak nu klart fører. Min kode gik udelukkende ud fra at der skulle slettes rækker, og der fører jeg stadig.
Og så tunet en smule: (ps: akyhne: er dine tider fra før i min eller sekunder?)
Sub alternativ() Dim i As Long Dim Slut As Long Dim t As Long 'Start timer t = Timer
Application.ScreenUpdating = False 'slå så automatisk kalkulation fra Application.Calculation = xlCalculationManual
Slut = Range("C63536").End(xlUp).Row 'indsæt sorteringskolonne og indsæt formel der giver rækkenummer Range("BB1") = "1" 'fyld nedad Range("BB1").DataSeries Rowcol:=xlColumns, Type:=xlLinear, Step:=1, Stop:=Slut
'Hvis summen af C,D,og E er 0, så fjern alt indhold i rækken With Application.WorksheetFunction For i = 2 To Slut If .Sum(Range("C" & i & ":E" & i)) = 0 Then Rows(i).Clear Next End With
'Sorter nu på den indsatte kolonne med rækkenumre Range("B1:BB" & Slut).Sort Key1:=Range("BB1"), Order1:=xlAscending, Header:=xlGuess, _ OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom, _ DataOption1:=xlSortNormal
'Ryd så den indsatte kolonne Range("BB:BB").Clear 'sæt skærmopdatering og kalkulation til igen Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True 'vis timeren MsgBox Timer - t End Sub
Men den kan selvfølgelig ikke følge med en sortering. Din nye kode kan jeg knap nok må at måle med 5.000 celler. 20.000 celler, 50% tager ca. 3,3 sekunder mod...
Koden kunne sikker også gøres lidt mere forstået. Udgangspunktet var bare at slette så mange rækker som muligt. Excel sætter åbenbart en grænse for, hvor lang stringen i et range må være. Derfor max. 20 ranges ved over 10.000 rækker, og 25 ved under 10.000.
Ideen med 20 range af gange er heller ikke så dum ser det ud til. den kan måske bruges i et andet afsnit :-) (Bærbar ibm R51 - 1.5Ghz centrino - 512 Ram)
baks er godt nok hurtig, men en sortering løser ikke mine ønsker, da enkeltrækkerne hører sammen i en hierarki-struktur, som fuldstændig bliver smadret med en sortering.
Så, akyhne, din kode er hurtigst til formålet, men det var primært enkelthed (og forklarlighed), jeg efterspurgte, selvom hastighed bestemt også er en faktor.
Jeg har fået løst mit problem og kører videre med kabbaks kode - så mange tak for den! Derudover har jeg lært en masse, og det aftvinger jo en del ærefrygt, når titanerne på feltet støder sammen på skærmen!
Jeg har oppet pointene og vil nu give 100 til kabbak og 50 til hver af akyhne og bak for anstrengelserne, hvis akyhne også lægger et svar.
x-lars -> hvis du lægger mærke til det, ændrer min kode på intet tidspunkt på din sortering. Det er netop derfor at jeg indsætter en kolonne med alle rækkenumrene, som jeg så sorterer på.
Jep, bak, du har - som sædvanligt - ret. Det var min formatering af tabellen (betinget), der gik helt fløjten. Tallene var intakte, men kom til at se meget mærkelige ud.
er testet på et tomt ark på nær de 200000*3 celler med =1+1 eller =0 (50% 3 ca sek) så har du mange beregninger, skal beregning nok slås fra ved sammenligning Application.Calculation = xlCalculationManual
Jeg lavede i weekenden også nogle test hvor jeg looper gennem hver kode. Her er testen med gem mellem hver kodeafvikling. Loop 4 gange - 5.000 celler 50%:
min test hvis jeg husker ret med 20000*3 celler hvor 10000 indeholdt formlen =1+1 fra 1 til 5000 og fra 15000 til 20000 og 10000 indeholdt formlen =0 fra 5000 til 15000 min ca 2 sek bak ca 4 sek akyhne ca 6 sek kabbak minutter
Sub GenSkabTabel() With Worksheets(1) .Range("B1") = "Overskrift 1" .Range("B1").AutoFill Destination:=.Range("B1:E1") .Range("G1") = 5 .Range("B2") = "Test 1" .Range("C2").Formula = "=mod(row(),$G$1)" .Range("D2").Formula = "=c2" .Range("E2").Formula = "=c2" .Range("B2:E2").AutoFill Destination:=.Range("B2:E20000") .Calculate End With End Sub
I princippet burde excellent's kode og min første kode være nogenlunde lige hurtige da de sletter på samme måde (tilsidst) og det er selve sletningen der tager tiden og ikke loopet. Ved større områder burde Akyhne kode være hurtigst idet der jævnt hen er frigivet mere hukommelse. Jeg tror at grunden til at excelent kode i hans egen opstilling er hurtig, skyldes at der er sammenhængende rækker der slettes.
Hvad siger I så til loopresultatet, hvor der ikke gemmes mellem hver loop (25/09-2006 15:32:21)? Tiderne svinger jo uhyggelig. Fri systemhukommelse lå konstant på 184-186MB, og swapfilen ændrede ikke størrelse! Og hvorfor stiger alle resultater ved loop, uden gem?
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.