Avatar billede fly__one Nybegynder
02. maj 2011 - 10:17 Der er 10 kommentarer

Effektivisere vba-kode

Hej

Jeg har følgende vba-kode som jeg anvender til at periodisere nogle omkostninger.

Problemet er at den er for tung og langsom.

Mit spørgsmål er om der er nogen der kan pege på nogle løsninger, der kan forbedre hastigheden markant?

Den er ikke særlig kompliceret men lang pga. en masse if-else

----
Option Base 1
Function PLversion1(TmStart, TmSlut, CF, RGdato, Uddata)
Dim TerminAct As Integer, Antal As Integer, Dage As Integer
Dim PL As Double
Dim x As Integer, z As Integer

If IsError(CF) Then
Exit Function
End If

TerminAct = TmSlut - TmStart
Dim c(13, 1) As Double
c(1, 1) = Application.WorksheetFunction.VLookup(TmStart, Range("DaysRG"), 2, False)
For z = 2 To 13
c(z, 1) = Application.WorksheetFunction.VLookup(c(z - 1, 1), Range("DaysRG2"), 2, False)
Next

For z = 1 To 13
If c(z, 1) < TmSlut Then
Antal = Antal + 1
End If
Next

        If Antal = 0 Then
            If RGdato = c(1, 1) Then
            Dage = TmSlut - TmStart
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 1 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = TmSlut - c(1, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
           
        ElseIf Antal = 2 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = TmSlut - c(2, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
           
        ElseIf Antal = 3 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = TmSlut - c(3, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 4 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = TmSlut - c(4, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If

        ElseIf Antal = 5 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = TmSlut - c(5, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If

        ElseIf Antal = 6 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = TmSlut - c(6, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 7 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = TmSlut - c(7, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
     
        ElseIf Antal = 8 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = c(8, 1) - c(7, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(9, 1) Then
            Dage = TmSlut - c(8, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 9 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = c(8, 1) - c(7, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(9, 1) Then
            Dage = c(9, 1) - c(8, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(10, 1) Then
            Dage = TmSlut - c(9, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 10 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = c(8, 1) - c(7, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(9, 1) Then
            Dage = c(9, 1) - c(8, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(10, 1) Then
            Dage = c(10, 1) - c(9, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(11, 1) Then
            Dage = TmSlut - c(10, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
           
        ElseIf Antal = 11 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = c(8, 1) - c(7, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(9, 1) Then
            Dage = c(9, 1) - c(8, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(10, 1) Then
            Dage = c(10, 1) - c(9, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(11, 1) Then
            Dage = c(11, 1) - c(10, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(12, 1) Then
            Dage = TmSlut - c(11, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        ElseIf Antal = 12 Then
            If RGdato = c(1, 1) Then
            Dage = RGdato - TmStart
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(2, 1) Then
            Dage = c(2, 1) - c(1, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(3, 1) Then
            Dage = c(3, 1) - c(2, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(4, 1) Then
            Dage = c(4, 1) - c(3, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(5, 1) Then
            Dage = c(5, 1) - c(4, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(6, 1) Then
            Dage = c(6, 1) - c(5, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(7, 1) Then
            Dage = c(7, 1) - c(6, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(8, 1) Then
            Dage = c(8, 1) - c(7, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(9, 1) Then
            Dage = c(9, 1) - c(8, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(10, 1) Then
            Dage = c(10, 1) - c(9, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(11, 1) Then
            Dage = c(11, 1) - c(10, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(12, 1) Then
            Dage = c(12, 1) - c(11, 1)
            PL = Dage / TerminAct * CF
            ElseIf RGdato = c(13, 1) Then
            Dage = TmSlut - c(12, 1)
            PL = Dage / TerminAct * CF
            Else
            PL = 0
            End If
       
        End If
       
Select Case Uddata
Case Is = "PL"
PLversion1 = PL
Case Is = "DAYS"
PLversion1 = Dage
End Select

End Function
Avatar billede Loga2011 Nybegynder
02. maj 2011 - 10:38 #1
Jeg kender ikke til VBA men har alligevel et forslag sådan lidt mere generelt om databaser / datamængder.

En mulighed for optimering er hvis du har mulighed for at begrænse datamængden inden du udfører beregningen/kommandoen. Sørg for at der ikke indgår gamle data, som er uinteressante for denne beregning, så vil det gå hurtigere.
Avatar billede tubber Juniormester
02. maj 2011 - 11:09 #2
Nu sidder jeg og kigger lidt på koden og for mig ser det ud til de nederste if er ens, bortset fra at hæves antal er den magen til if'en før men med en linie mere, er det korrekt ?

For mig ser det ud til du laver en masse unødvendige beregninger, lav dem fra start 1 gang for alle og smid dem i et array eller i 12 variabler (går ud fra felterne i din excell ikke er konstante).

/Tubber
Avatar billede iver_mo Nybegynder
02. maj 2011 - 11:15 #3
Tag et kig på http://www.ozgrid.com/VBA/select-case.htm for at se hvordan select case virker. select case burde være hurtigere når du har så mange else if'er.

Hvis jeg skulle effektivisere så ville jeg starte helt forfra med arket, da jeg forestiller mig at det må være muligt at lave en struktur så man kan undgå de mange if'er.
Avatar billede fly__one Nybegynder
02. maj 2011 - 11:55 #4
tak for kommentarer. Jeg tror måske det er nemmere for jer at hjælpe hvis jeg konkretiserer opgaven...

data input i funktion:

perioden er 23-Feb-2016    23-Feb-2017 (kan være alle fra 1 måned til 12 måneder)
beløb på 5000000

opgaven er at fordele de 5000000 med skæring pr. d. 25. undtagen i dec hvor skæring er d. 31. dvs.

pr.25.feb 2016
(25-02-16 minus 23-02-16)/(23-02-17 minus 23-02-16)*5000000

pr.25. marts 2016
(25-03-16 minus 25-02-16)/(25-2-16 minus 25-01-16)*5000000

osv.

håber det giver lidt mere info
Avatar billede fly__one Nybegynder
02. maj 2011 - 12:37 #5
lige en til kommentar - en af de ting jeg leder efter svar på er (måske ikke helt klart beskrevet) er hvilke ting jeg kan effektivisere. Ingen jeg går i går. Med andre ord hvad vil have den største effekt at ændre....
Avatar billede iver_mo Nybegynder
02. maj 2011 - 13:23 #6
Tror jeg har en fornuftig metode til det. Poster snart.
Avatar billede Tryphon Nybegynder
02. maj 2011 - 13:58 #7
En select case ville være at foretrække fremfor alle dine elseif'er, men den giver ikke meget hastighed. Dit problem ligger i, at du indlæser dit array c() ind ved hjælp af vlookup formler. Den skal læse og skrive til arket hele tiden, og det er det, der tager tid. Jeg ville indlæse hele mit dataområde i array c, således at den ligger i RAMmen og så lave en funktion, der gennemsøger arrayet efter antal.

Du kan evt. bruge nedenstående funktion til at hente data. Records vil være dit c-array. StartCell skal du skrive som f.eks. "a1" og ikke som en range.

Function DataRange_SheetByString_CurrentRegion_Var(ByRef records() As Variant, ByVal SheetName As String, ByVal StartCell As String)
Dim Table As Range

    Set Table = Worksheets(SheetName).Range(StartCell).CurrentRegion
    records() = Table.Value
    Set Table = Nothing
End Function

Jeg har desværre ikke tid til at lave hele koden for dig, men det burde hjælpe dig lidt på vej.
Avatar billede fly__one Nybegynder
03. maj 2011 - 10:12 #8
@ iver_mo poster du snart din metode :)

@ Tryphon jeg er ikke helt sikker på at jeg forstår din funktion. Er det et alternativ til excels opslags-funktion ???
Avatar billede Tryphon Nybegynder
03. maj 2011 - 11:07 #9
Ja, helt klart. Når du anvender Excels opslagsfunktion skal koden læse til og fra disk hele tiden, og det tager tid. Hvis du indlæser det hele i et array i et hug og arbejder i det, lægger du alle data i RAMmen, og så vil koden kører ekstremt meget hurtigere.

Du skal kalde min funktion fra din egen udelukkende med det formål at hente data ind i arrayet.

Dim c() as variant
DataRange_SheetByString_CurrentRegion_Var c(), ActiveSheet.Name, "A1" (eller anden celle indenfor dit data array)

erstatter

Dim c(13, 1) As Double
c(1, 1) = Application.WorksheetFunction.VLookup(TmStart, Range("DaysRG"), 2, False)
For z = 2 To 13
c(z, 1) = Application.WorksheetFunction.VLookup(c(z - 1, 1), Range("DaysRG2"), 2, False)
Next

Bemærk, at dit array er en Variant istedet for Double. Du kan evt. justere koden, så det passer til Double.
Avatar billede Tryphon Nybegynder
03. maj 2011 - 12:13 #10
Bemærkede lige din tmstart og tmslut, så måske denne funktion passer dig bedre.

Kald den som

DataRange_SheetByString_DataRange_Var c(), ActiveSheet.name, tmstart, 1, tmslut, 1

forudsat tmstart og tmslut refererer til rækkenumre.

Function DataRange_SheetByString_DataRange_Var(ByRef records() As Variant, ByVal SheetName As String, _
  ByVal FirstRow As Long, ByVal FirstColumn As Integer, ByVal LastRow As Long, ByVal LastColumn As Integer)
Dim Table As Range

    Set Table = Worksheets(SheetName).Range(Cells(FirstRow, FirstColumn), Cells(LastRow, LastColumn))
    records() = Table.Value
    Set Table = Nothing
End Function
Avatar billede Ny bruger Nybegynder

Din løsning...

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.

Loading billede Opret Preview
Kategori
Vi har et stort udvalg af Excel kurser. Find lige det kursus der passer dig lige her.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester