Avatar billede sjap Praktikant
17. september 2002 - 11:39 Der 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
17. september 2002 - 11:49 #1
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
Avatar billede benson Nybegynder
17. september 2002 - 11:54 #2
flemmingdahl> Er det i princippet ikke en god ide at step-ændre sit ARRAY.

Altså at øge Redim'e i steps af f.eks. 50-100 stk.
Fordel : det foregår hurtigere
ulempe : der kan være et lille overskud i Array
benson
Avatar billede sjap Praktikant
17. september 2002 - 11:59 #3
Det ser umiddelbart spændende ud, men der går lige op til et par timer inden jeg kan se nærmere på forslaget (møde og den slags seriøst pjat)  :-)
17. september 2002 - 11:59 #4
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
17. september 2002 - 12:02 #5
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.
Avatar billede sjap Praktikant
17. september 2002 - 16:21 #6
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?
Avatar billede sjap Praktikant
17. september 2002 - 16:40 #7
Der er godt nok kommet fart på denne del af programmet. Mange tak for hjælpen.
Avatar billede bak Forsker
17. september 2002 - 18:27 #8
superjab-> hvorfor skal der sorteres bagefter ?
Avatar billede bak Forsker
17. september 2002 - 18:44 #9
Ø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
Avatar billede sjap Praktikant
17. september 2002 - 18:45 #10
bak

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).
Avatar billede sjap Praktikant
17. september 2002 - 18:50 #11
bak

Jeg glemte måske at nævne, at felterne ikke altid er tomme - der kan stå tekst (både mellemrum og blot en ' ). Vil de blive talt med i

Application.WorksheetFunction.Count(dataområde)
Avatar billede sjap Praktikant
17. september 2002 - 19:16 #12
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 :-)
Avatar billede sjap Praktikant
17. september 2002 - 19:22 #13
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.
Avatar billede bak Forsker
17. september 2002 - 19:54 #14
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 


/bak
Avatar billede bak Forsker
17. september 2002 - 19:55 #15
har du en emailadr. så har jeg en superhurtig sorteringsalgoritme på regneark fra guruen j. walkenback
Avatar billede sjap Praktikant
17. september 2002 - 21:41 #16
Tak for den gode forklaring jeg tror faktisk jeg forstod det :-)

Min e-mail adresse er: jap@privat.tele.dk
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
Excel kurser for alle niveauer og behov – find det kursus, der passer til dig

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