17. september 2002 - 11:39Der er
15 kommentarer og 1 løsning
Overføre område til array i VBA
Jeg har et lille program hvor jeg laver nogen beregninger ud fra data i et område af et regneark. I et andet spørgsmål er jeg blevet lidt overrasket over hvor enkelt ting kan laves, så nu vil jeg lige høre om der er en enklere måde at lave nedenstående på.
Først tæller jeg blot hvor mange celler der er TAL i og så redim'er jeg arrayet og derefter overføres værdierne til arrayet. Data skal derefter sorteres (i øvrigt med min egen qsort, der er væsentligt hurtigere end den vist i http://www.eksperten.dk/spm/250778) så derfor vil jeg kunne have celler indeholdende tal med i arrayet.
For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then AntalData = AntalData + 1 End If End If Next ReDim DataMatrix(AntalData) As Double
Indeks = 0 For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then Indeks = Indeks + 1 DataMatrix(Indeks) = c.Value End If End If Next
Jeg har ikke testet det, men først smider jeg alle celle adresserne ind i en collection, og efterfølgende bruger jeg denne collection til at smide dataene ind i Array'et.
Dim colCells As Collection Dim vntCell As Variant Set colCells = New Collection
For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then colCells.Add c.Address AntalData = AntalData + 1 End If End If Next ReDim DataMatrix(AntalData) As Double
Indeks = 0 For Each vntCell In colCells DataMatrix(Indeks) = Range(colCells(Indeks + 1)).Value Indeks = Indeks + 1 Next
Det kan dog gøres hurtigere: For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then AntalData = AntalData + 1 ReDim Preserve DataMatrix(AntalData) DataMatrix(AntalData) = c.Value End If End If Next
I ovenstående eks burde det nok se således ud, således der ingen overskud blev slettet igen.
For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then AntalData = AntalData + 1 ReDim Preserve DataMatrix(AntalData) DataMatrix(AntalData) = c.Value End If End If Next Redim Preserve DataMatrix(AntalData - 1)
Det kunne nu meget nemt laves med en Collection: Dim colCells As Collection Set colCells = New Collection For Each c In DataOmråde If Not IsEmpty(c) Then If IsNumeric(c) Then colCells.Add c.Value End If End If Next
benson>> du kan sagtens lave en Redim DataMatrix(999) og efterfølgende Redim Preserve så array'et passer, men du vil ikke kunne mærke nogen væsentlig hastighedsforskel.
Uha der er fart på!! (har lige prøvet den, der ikke er collection baseret).
Har lige brugt en lille time på at finde ud af hvorfor min funktions resultater nu afviger lidt fra tidligere (lavede også en manuel beregning, der vist at den gamle funktion virkede korrekt) . Det viste sig at være på grund af
Redim Preserve DataMatrix(AntalData - 1)
"-1" skal bare fjernes så virker det som det skal. Var der nogen speciel tanke bag de -1 eller var det bare et lille uheld?
Ønsker du endnu mere speed skulle du prøve denne. Hele Dataområdet læser ind i an variantarray (dataarray) i en sætning. derefter læses det hele over i Datamatrix. Dette gør at man slet ikke har nogen operationer der indvolverer celler, men kun arrayoperationer og det går stærkt. Jeg testede lige med et dataormåder på 65000 * 4 celler og på enp350 tog det 3,1 sek. En anden ting er at jeg bruger Application.WorksheetFunction.Count(dataområde) til at dimensioner Datamatrix. Denne function tæller nemlig ikke tomme.
Sub test3(dataområde As Range) Dim antaldata As Long Dim dataarray, x As Long, y As Integer, z As Long antaldata = Application.WorksheetFunction.Count(dataområde) ReDim datamatrix(antaldata) dataarray = dataområde For x = 1 To UBound(dataarray, 1) For y = 1 To UBound(dataarray, 2) If Not IsEmpty(dataarray(x, y)) And IsNumeric(dataarray(x, y)) Then datamatrix(z) = dataarray(x, y) z = z + 1 End If Next Next End Sub
Jeg har en funktion, der beregner fraktiler. Den indbyggede funktion er ikke korrekt til formålet. I den indbyggede fraktil er en største værdi 100% fraktilen, men det er - så vidt jeg har forstået - ikke statistisk korrekt.
Det jeg skal bruge sorteringen til, er at finde den n'te største værdi (hvor n afhænger af den ønskede fraktil).
Hvordan f.. gør i det? Først leverer flemmingdahl kode, der er 2-3 gange hurtigere end min egen (som jeg selv synes var ok - men ikke fantastisk) og nu følger bak så op med kode der er yderligere X gange hurtigere. Der skulle 500.000 data til for at jeg kunne registrere 5 sek. for bak og jeg venter stadig på at flemmingdahls skal blive færdig - godt det ikke er min egen kode de er oppe mod :-)
OK i det valgte tilfælde blev forskellen hele 54 gange - det var dog utroligt.
Bak Kan du ikke lige prøve om du kan forklare For-løkkerne for mig, for jeg synes ikke helt jeg forstår. Jeg opretter gerne et nyt spørgsmål til formålet. Jeg synes det er blevet ret spændende det her.
Selve for / next løkken svarer stort set til din metode. Det, der giver hastighed, er at jeg istedet for at læse hvad der står i cellerne een for een indlæser alle celler i et (variant)array på een gang. Det er notorisk langsommere at læse celler end at læse array. ******* et hug.... dataarray = dataområde ******* Hvis dit dataområde er 1000 rækker * 5 kolonner vil dataarray automatisk blive en todimensionel matrix på dataarray(1000,5) indeholdende alle værdier fra Dataområde. Da du skal bruge en en-dimensionel matrix er jeg nødt til at overføre disse data til et nyt array (Datamatrix) Det gøres så i løkken
For x = 1 To UBound(dataarray, 1) For y = 1 To UBound(dataarray, 2) If Not IsEmpty(dataarray(x, y)) And IsNumeric(dataarray(x, y)) Then datamatrix(z) = dataarray(x, y) z = z + 1 End If Next Next
UBound(dataarray, 1) returnerer så 1000 UBound(dataarray, 2) returnerer så 5 Dette er jo bare størrelsen på Dataarray
If Not IsEmpty(dataarray(x, y)) And IsNumeric(dataarray(x, y)) svarer nøje til dit eget check med tomme og kun numeriske værdier.
datamatrix(z) = dataarray(x, y) z = z + 1
her læses data fra variantmatrixen over i dim en-dimensionelle Datamatrix
ps. man kan forøvrig også sætte data ind i regnearket lynhurtigt på denne måde.. bare vend sætningen dataområde=dataarray
Tak for den gode forklaring jeg tror faktisk jeg forstod det :-)
Min e-mail adresse er: jap@privat.tele.dk
Synes godt om
Ny brugerNybegynder
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.