Avatar billede folj Forsker
08. august 2016 - 12:23 Der er 14 kommentarer og
3 løsninger

Excel-VBA: Flere måder at få data ind i array på?

Er der flere måder at få data ind i et array på?

Standardmåden jeg kender til VBA er måden:
MyArray = Array("Apples", "Bananas", "Oranges", "PineApples")


Jeg vil dog gerne, efterhånden som jeg looper igennem nogle data, pille nogle ud der opfylder bestemte kriterier og smide dem ind i et array.

I andre programmeringssprog der er meget fleksible kan man lave noget i retning af
MyArray[] = "Apples"
MyArray[] = "Bananas"
MyArray[] = "Oranges"
MyArray[] = "PineApples"

og opnå det samme som i førnævnte array

Når jeg looper og finder data der matcher mine kriterier, så kender jeg oftest ikke størrelsen på arrayet, fordi der først er efter gennemløbet jeg kender mængden at data der matchede.
Avatar billede Jessen Seniormester
08. august 2016 - 12:36 #1
Hej,

Her er et eksempel, som fylder dit array med cellerne A1 til A10

Sub test()

Dim MyArray(10) As Integer

For i = 1 To 10
    MyArray(i) = Cells(i, 1)
Next

End Sub

Du kan placere de betingelser du ønsker inde i for-loopet.
Option base 1, betyder at dit array starter fra 1 og ikke fra 0. Det kan jeg personligt godt lide at bruge.
Avatar billede Jessen Seniormester
08. august 2016 - 12:37 #2
Her er koden igen

Option Base 1

Sub test()

Dim MyArray(10) As Integer

For i = 1 To 10
    MyArray(i) = Cells(i, 1)
Next

End Sub
Avatar billede folj Forsker
08. august 2016 - 12:44 #3
@Jessen
Undskyld, hvis jeg trykte mig dårligt ud...

Jeg har behov for attilføje en data mere til arrayet for hvert loop (hvis nogle kriterier er opfyldt), og derfor kender jeg ikke størrelse på array i forvejen...
Avatar billede Jessen Seniormester
08. august 2016 - 12:48 #4
Helt ok,

Du kan bruge funktionen redim()

Dette eksempel laver tilpasser array-størrelsen til antallet af rækker i området under under celle A1:

Option Base 1

Sub test()

Dim MyArray() As Integer

n = Range("A1").CurrentRegion.Rows.Count

ReDim MyArray(n)

For i = 1 To 10
    MyArray(i) = Cells(i, 1)
Next

End Sub
Avatar billede folj Forsker
08. august 2016 - 13:13 #5
Prøv lige at kommereter hvad ddu gør undervej i din kode...
1. Du sætter n til værdien 1 med Range("A1").CurrentRegion.Rows.Count
2. derefter redimentionerer du array til 1
3. så prøver du at løbe arrayet igennem med 10 loops, men den fejler jo allerede i andet loop når arrayet er redimentioneret til 1
Avatar billede Jessen Seniormester
08. august 2016 - 13:24 #6
Ja, jeg beklager - det var en rest fra første udkast, så det virker naturligvis ikke.

Hvis du retter 10 til 'n' i loopet, så skulle de problem være løst. Så vil løkken kun køre én gang, hvis der ikke står noget i celle A1.

Sub test()

Dim MyArray() As Integer

n = Range("A1").CurrentRegion.Rows.Count

ReDim MyArray(n)

For i = 1 To n
    MyArray(i) = ThisWorkbook.Sheets("Ark1").Cells(i, 1)
Next

End Sub
Avatar billede kabbak Professor
08. august 2016 - 13:57 #7
MyArray = ThisWorkbook.Sheets("Ark1").Range(Cells(1, 1), Cells(Range("A1").CurrentRegion.Rows.Count, 3)) ' indlæser kolonne A B og C i array, og kun brugte rækker
Avatar billede folj Forsker
08. august 2016 - 13:59 #8
@Jessen
Jeg kan ikke se at dit forslag løser det jeg søger...
Jeg har lige omskrevet dit forslag lidt for at se om det er muligt at tilføje en ny tom plads i arrayet med ReDim, for så vil jeg jo ad den omvej kunne tilføje en ny værdi for hvert loop.
Når jeg tester med nedenstående kode der anvende ReDim på mit array, så kan jeg konstatere at arrayet mister sine allerede  eksisterende værdier. Prøv lige selv at teste både med linien ReDim slået til og fra med kommentartegnet '


Sub TestAddToArray1()

Dim MyArray() As Variant
Dim ArrayCount As Integer
MyArray = Array("Apples", "Bananas", "Oranges", "PineApples")

ArrayCount = UBound(MyArray, 1)

'ReDim MyArray(ArrayCount + 1) ' tilføjer en ekstra plads i MyArray

MsgBox "Array har nu størrelsen " & UBound(MyArray, 1) & " startende med index 0"

For i = 0 To UBound(MyArray, 1)
  MsgBox "Værdi på arryets nøgle " & i & " er " & MyArray(i)
Next i

End Sub
Avatar billede Jessen Seniormester
08. august 2016 - 14:02 #9
Hej,

Det er rigtigt, at redim tømmer dit array. Jeg troede, at du kunne sætte størrelsen til en start, og så ville det virke.

Hvis du skal ændre størrelse efter dit array har fået data, skal du skrive "ReDim Preserve" i stedet for blot "Redim". Så skulle dit array beholde sit indhold.
Avatar billede supertekst Ekspert
08. august 2016 - 15:43 #10
Måske:
Indsætte "de relevante data" i en String variabel m/skilletegn efter "hver match".
Når udtræk er afsluttet - Split tekststrengen via skilletegnet i en variabel af typen Variant.
Ubound(Varianten) som mål for antal elementer.
Avatar billede folj Forsker
09. august 2016 - 09:18 #11
@Jessen

Ja det ændrede jo det hele at vi fik ændret ReDim til ReDim Preserve.

Nu lykkes det at udvide arrayet med en ekstra plads uden at miste oprindelige data.
Det betyder at jeg kan gøre det "on the fly" når jeg looper data igennem. Alletiders.

Min lille test-procedure kommer derfor til at se således ud.
Sub TestAddToArray1()

Dim MyArray() As Variant ' erklærer mit array
Dim ArrayCount As Integer
MyArray = Array("Apples", "Bananas", "Oranges", "PineApples") ' og lægger data i mit array

ArrayCount = UBound(MyArray, 1) ' måler størrelsen på mit array
MsgBox "oprindelig størrelse på Array er " & ArrayCount & " startende med index 0"

ReDim Preserve MyArray(ArrayCount + 1) ' udvider med en ekstra plads i MyArray

MsgBox "Array har nu størrelsen " & UBound(MyArray, 1) & " startende med index 0"
For i = 0 To UBound(MyArray, 1)
  MsgBox "Værdi på arryets nøgle " & i & " er " & MyArray(i)
Next i

End Sub


Tak for hjælpen
Avatar billede bvirk Guru
09. august 2016 - 18:23 #12
vba er 20 år gammelt og meget low-level simpelt. Det betyder ikke så meget når man anvender de office objekter der løser opgaven (som cells og range i excel), men når det kommer til arrays er det værd at efterligne de features fra andre sprog der fungerer på et højere nivea.
Eksempelvis javascripts 'push'

Først en function der returnere strengrepræsentationen af arrayet - til testudskrift i immediate vinduet - der arbejdes med 1 dimensionelle men potentielt
ragged arrays (array indhold kan være arrays - også recursivt)

Function arr2str(arr, Optional indent = 0)
´´´´Dim i, ai
´´´´For Each i In arr
´´´´´´´´If IsArray(i) Then
´´´´´´´´´´´´arr2str = arr2str & arr2str(i, indent + 1)
´´´´´´´´Else
´´´´´´´´´´´´arr2str = arr2str & "n" & indent & "> " & Space(4 * indent) & i & vbCrLf
´´´´´´´´End If
´´´´Next
End Function

IMMEDIATE
?arr2str(array(12,array(2,3,4),"trala"))
n0> 12
n1>´´´´´2
n1>´´´´´3
n1>´´´´´4
n0> trala


Sub push(V, i, Optional rLevel = 0)
´´´´Dim ai
´´´´If IsArray(i) And (rLevel <> 0) Then
´´´´´´´´For Each ai In i
´´´´´´´´´´´´push V, ai, rLevel - 1: Next
´´´´Else´´´´
´´´´´´´´If IsEmpty(V) Then V = Array()
´´´´´´´´ReDim Preserve V(UBound(V) + 1)
´´´´´´´´If IsObject(i) Then Set V(UBound(V)) = i Else V(UBound(V)) = i
´´´´End If
End Sub

Function flatArray(jaggedThing)
´´´´push flatArray, jaggedThing, -1
End Function

Med disse:
Function test1()
´´´´push test1, 3
´´´´'other codelines
´´´´push test1, "små"
´´´´push test1, "kinesere"
End Function

Function test2()
´´´´Dim myVar
´´´´'VIGTIGT - DIMENSIONSLØST ARRAY - ikke myVar()
´´´´push myVar, 3
´´´´push myVar, Array("små", "kinesere")
´´´´test2 = myVar
End Function

Prøv i immediate vinduet
?arr2str(test1())

?arr2str(test2())

?arr2str(flatarray(test2()))
Avatar billede bvirk Guru
09. august 2016 - 18:28 #13
Alle ' tegn i #11 skal natuligvis erstattes med mellemrum - kan ikke umiddelbart se hvordan man layouter indrykning her på eksperten.
Avatar billede folj Forsker
12. august 2016 - 12:52 #14
Nu hvor jeg vil bruge det i praksis har jeg krerert min egen function til at måle arrayets størrelse, tilføje en post og smide en værdi ind på den tilføjede post.


Function AddToArray(MyArray() As Variant, Addition As String)
' function der modtager et enkeldimentionelt array og tilføjer en post hvori der smides en tekststreng

Dim ArrayCount As Integer

ArrayCount = UBound(MyArray, 1) ' måler størrelsen på mit array

ReDim Preserve MyArray(ArrayCount + 1) ' udvider med en ekstra plads i MyArray

MyArray(ArrayCount + 1) = Addition ' smider den tekststreng der skulle tilføjes ind på sidste plads

AddToArray = MyArray

End Function


Og i proceduren herunder laver jeg først mit array med 4 poster (strings), hvorefter jeg med min egen function udvider arrayet med en post og tilføjer en ekstra post.

Sub TestAddToArray()

Dim MyArray() As Variant
Dim ArrayCount As Integer
MyArray = Array("Apples", "Bananas", "Oranges", "PineApples")
Dim InsertValue As String

ArrayCount = UBound(MyArray, 1)
InsertValue = "FruitNr_" & 5 ' sammensætter den værdi jeg vil tilføje til arrayet

MyArray = AddToArray(MyArray, InsertValue) ' her laver jeg functionskaldet hvor jeg tilføjer en post

'herunder løber jeg lige arrayet igennem og svarer med en msgbox på hvad hver enkelt post indeholder
For i = 0 To UBound(MyArray, 1)
  MsgBox "Værdi på arryets nøgle " & i & " er " & MyArray(i)
Next i

End Sub
Avatar billede folj Forsker
12. august 2016 - 12:56 #15
@bvirk
Jeg forstår ikke het dit indlæg #12, men jeg tænker at det er en måde at udskrive et array på.

Jeg forstår det blot ikke il bunds, men åske det skylde at je aldrig er blevet helt fortrolig med immediate-vinduet...
Avatar billede folj Forsker
12. august 2016 - 13:02 #16
Undskyld. der skal vist et nyt batteri i mit tastatur.
der skulle stå:
Jeg forstår det blot ikke til bunds, men måske det skyldes at jeg aldrig er blevet helt fortrolig med immediate-vinduet...

Det er vist ikke batteriet (mit tastatur er jo ikke trådløst).
Jeg tror snarere det er den javascript-baserede formular som vi skal skrive vores kommentarer i, der driller.
Avatar billede bvirk Guru
12. august 2016 - 16:47 #17
En eller anden måde at nedbryde til mindre dele og teste disse isoleret, er en del af at programmere.
Funktion arr2str bruges i #12 til udskrift af et array i immediate vinduet - på den måde kan array test resultater vises
I Excel kan man også udskrive til celleområder, men det er enklere at småtest udskrive til immediate (dansk: brugerudtryk) vinduet og kodelinierne illusterer enklere hvad der sker.
Jeg kan se at jeg har gjort det sværere at forstå, ved at give en vis kontrol med tilføjelse af array's til array -jeg ku ikke lade være ;)
Bemærk at jeg bruger funktionsnavnet som eneste variabel - denne returnere et array med elementerne 1, 2 og 3.

Function f()
    f=array(1,2,3)
End Function

  eller

Function f()
    push f,1
    push f,2
    push f,3
End Function

?f()(1),ubound(f())
2            2
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

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