Anzeige
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Excel VBA | Array & Dictionary

Forumthread: Excel VBA | Array & Dictionary

Excel VBA | Array & Dictionary
03.09.2018 23:19:02
Florian
Servus zusammen,
ich habe ein kleines Excel VBA Problem, das vielleicht gar keines ist.
Die Subroutine sollte eigentlich nur 2 Datensätze vergleichen und den zweiten Datensatz vervollständigen und zurück in den Worksheet schreiben.
Zum Verständnis, in der Tabelle "MSRBSCell" stehen Parameter A & B, in der Tabelle "PUCell" stehen Parameter B & C.
Ergebnis am Ende, Tabelle "PUCell" mit Parameter A komplettieren und dann am Ende einen String generieren. (Die String Generation wird im Moment noch per Formel gelöst)
Das Problem ist eher die Menge der Daten.
MSRBScell = 220.000 Zeilen
PUCell = 270.000 Zeilen
Ein kompletter Durchlauf braucht im Moment 30min.
Wenn ich die Anzahl der Zeilen auf 10.000 reduziere läuft das Script 3 Sekunden.
bei 20.000 = 10s
bei 50.000 = 1:11 min
.
.
.
bei 250k = 30 min
Das Dictonary hab ich für dieses Script schon immer benutzt, die Array's sind neu. Geschwindigkeitsunterschied zu ohne Array geht richtung 0.
Vielleicht hat jemand von euch eine Idee.
PUCell_end = 20000 'PUCell.Cells(Rows.Count, 3).End(xlUp).Row + 1
MSRBSCell_end = 20000 'MSRBSCell.Cells(Rows.Count, 1).End(xlUp).Row
arrDict = MSRBSCell.Range("A2:D" & MSRBSCell_end).Value2
timetaken = Now()
For i = 1 To UBound(arrDict)
With Mydic1
On Error Resume Next:
.Add arrDict(i, 4), arrDict(i, 1)
If Err.Number  0 Then .Item arrDict(i, 4), arrDict(i, 1)
On Error GoTo 0
End With
Next i
arrDict = Empty
timetaken = Now() - timetaken
Debug.Print "Dict: ", timetaken
arrTest = PUCell.Range("B2:J" & PUCell_end).Value2
timetaken = Now()
For i = LBound(arrTest, 1) To UBound(arrTest, 1)
tmpNEID = arrTest(i, 4)
arrTest(i, 1) = Mydic1(tmpNEID)
Next i
PUCell.Range("B2:J" & PUCell_end) = arrTest
timetaken = Now() - timetaken
Debug.Print "Array & paste: ", timetaken
arrTest = Empty

Anzeige

16
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Excel VBA | Array & Dictionary
03.09.2018 23:40:35
Daniel
Hi
wie sieht denn die verarbeitungsgeschwindigkeit aus, wenn du folgendes machst:
1. Tabelle MSRBSCell nach Spalte B aufsteigend sortieren
2. in der Tabelle PUCell den Parameter A mit folgender Formel ergänzt (ich gehe mal davon aus, dass immer die Spalten A und B genutzt werden:
=Wenn(SVerweis(B1;MSRBSCell!B:B;1;1)=B1;Index(MSRBSCell!A:A;Vergleich(B1;MSRBSCell!B:B;1));"")
Sortieren, Formel einfügen und Formel durch Wert ersetzen solltest du bei VBA gut auch ohne Hilfe hinbekommen.
Das ist in der Regel sehr schnell, weil Excel im Sortieren sehr schnell ist und der SVerweis/Vergleich in Sortierten Daten ebenfalls.
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 00:01:50
Florian
Servus Daniel,
vielen Dank für deine Antwort.
In beiden Tabellen habe ich bereits nach den beiden Spalten die ich vergleiche sortiert, das passiert beim Import der Daten.
Dennoch ist deine Formel viel schneller und ist definitiv eine sehr gute Alternative.
Schon witzig, bin ja von den Formeln weg weil durch die vielen Daten und Worksheets alles sehr langsam wurde. Aber an temp Formeln hab ich nicht gedacht, bzw. hätte ich nicht gedacht das der Zeitunterschied so enorm ist.
Aber warum das mit dem Dictionary und dem Array so langsam ist kannst du dir auch nicht erklären?
Vor allem scheint es so als wird das Dict & Array langsamer je weiter man hochzählt:
Zeit stoppt immer nach 10k Zeilen.
Dict_k: 10000 00:00:00
Dict_k: 20000 00:00:03
Dict_k: 30000 00:00:04
Dict_k: 40000 00:00:06
Dict_k: 50000 00:00:08
Dict_k: 60000 00:00:09
Dict: 70000 00:00:43
Gruß
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 00:16:45
Florian
Hi,
hab wohl zu schnell geantwortet. Genau Übereinstimmung muss sein.
Dann dauerts wieder extrem lange. (5min ~ 20%)
Dann stell ich mal das Excel-Gut in Frage
04.09.2018 00:29:01
Daniel
denn meine Formel (dh die gesamte Formel) arbeitet mit genauer Übereinstimmung (die einzelneln Teilfuntkionen nicht, aber die gesamte Formel schon)
das hättest du eigentlich erkennen müssen.
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 00:22:41
Daniel
Hi
naja, das übertragen der Daten zwischen Array und Zellbereich hin und zurück braucht auch Zeit.
ggf kannst du deinen Dictionary-Code beschleunigen, wenn du nur die tatsächlich benötigten Daten in Arrays übernimmst und nicht die komplette Tabelle:
arrTest = PUCell.Range("B2:J" & PUCell_end).Value2
PUCell.Range("B2:J" & PUCell_end) = arrTest
hier liest und schreibst du 9 Spalten, obwohl es jeweils ausreichen würde, eine Spalte zu lesen(E) und eine zu schreiben (B)
du betreibst einfach zu viel unnötigen Aufwand, weil du 8 nicht benötigte Datenspalten einliest und 8 nicht benötigte, weil unveränderte Datenspalten wieder zurückschreibst.
klar brauchst du dann zwei Arrays, eins mit den Quelldaten und eines mit den Ergebnisdaten, aber die brauchen dann zusammen nur 1/4 der Datenmenge, die du jetzt verwendest und zurückgeschrieben in den Zellbereich wird sogar nur 1/8.
ebenso ist die Erstellung deines Dictionarys unnötig aufwendig.
Warum erstellst du die WITH-Klammer in der Schleife jedes mal neu?
Innerhalb der Schleife sollten nur Sachen ausgeführt werden, die sich in der Schleife auch ändern.
Alles was in der Schleife gleich bleibt, sollte wenn möglich schon ausßerhalb der Schleife ausgefürhrt werden, damit es nicht unnötig wiederholt wird.
aber das hier sollte eigentlich reichen:
For i = 1 To UBound(arrDict)
Mydic1(arrDict(i, 4)) =  arrDict(i, 1)
Next i
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 01:08:43
Florian
Hi,
das übertragen der Daten aus dem Worksheet in die Arrays ist mit Abstand die schnellste Operation im aktuellen zustand, dauert für beide Tabellen kleiner 0,2 Sekunden.
Selbst das zurückschreiben der 8 Spalten dauert kleiner 2 Sekunden.
Das ich alle/mehr Spalten rein kopiere als nötig hat natürlich den Grund das es einfacher ist, ich sicher bin das auch alle Daten wieder dahin kommen wo sie hingehören und das ich nicht weiß wie ich das Array ohne Schleife mit 2 Spalten befülle.
Wie würde man den jeweils nur die 2 benötigten Spalten in die Arrays schreiben. Ohne eine weiter schleife zu benutzen?
Das Dictionary benutze ich damit ich kein Match/Find oder ähnliches benutzen muss, und weil ich gelesen habe das die Suche nach Items über den Key das schnellste ist was man machen kann.
Als erstes habe ich versucht das Dictionary über .item zu füllen. Hier wird aber anscheinend im Dictionary gesucht ob der Key schon existiert (das hat das befüllen des Dict. noch um einiges langsamer gemacht). Darum habe ich .add genommen um die Prüfung zu umgehen und nur im Falle eines Fehlers auf .Item zurück zufallen. (Es sollten eigentlich keine Duplikate vorkommen (geschätzt sind es am ende kleiner 0,5% Duplikate)
Die with-klammer war noch in der Schleife weil ich probiert habe zu entstören und zu vergleichen.
Weiters verstehe ich nicht warum das modifizieren des Arrays im 2. Schritt so lange dauert. Hier wird ja rein gar nichts ausm Worksheet gelesen oder geschrieben. Alle Schreib & Lese Operationen finden im Array und im Dictionary statt.
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 01:49:11
Daniel
"Wie würde man den jeweils nur die 2 benötigten Spalten in die Arrays schreiben. Ohne eine weiter schleife zu benutzen?"
VBA gut ?
   arrTest = PUCell.Range("E2:E" & PUCell_end).Value2
timetaken = Now()
For i = LBound(arrTest, 1) To UBound(arrTest, 1)
tmpNEID = arrTest(i, 1)
arrTest(i, 1) = Mydic1(tmpNEID)
Next i
PUCell.Range("B2:B" & PUCell_end) = arrTest
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 10:17:49
Florian
2 Spalten je Array, die nicht zusammenhängend in der Tabelle stehen, zusammen ohne Schleife in das Array schreiben.
Schön das du mir vorwirfst keine Ahnung zu haben. Ist immer der konstruktivere Ansatz wenn man nicht weiter weiß.
AW: Excel VBA | Array & Dictionary
04.09.2018 10:26:46
Daniel
ich werfe dir nicht vor, keine Ahnung zu haben, ich stelle nur deine Selbsteinschätzung in Frage.
wie sieht deine Prüfung bezüglich meiner Formellösung aus?
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 11:11:14
Florian
wie gestern schon geschrieben, die Formel funktioniert erstaunlich gut. Und werde ich auch in Zukunft verwenden.
Dennoch, warum ist das hier:

For i = 2 To PUCell_end
tmpNEID = PUCell.Cells(i, 5)
PUCell.Cells(i, 2) = Mydic1(tmpNEID)
Next i
3 Sekunden schneller als das:
For i = LBound(arrTest, 1) To UBound(arrTest, 1)
arrTest(i, 1) = Mydic1(arrTest(i, 4))
Next i
für 50k Zeilen dauert die schleife die auf das Worksheet zugreift ~41 Sekunden.
wenn ich nur mit Array und Dictionary arbeite dann dauerts ~43 Sekunden und da habe ich das Array noch nicht gelesen oder zurückgeschrieben.
Wenn ich nicht 8 Spalten in ein Array schreibe sondern nur 1 und die 2. Spalte über ein weiteres Array erzeuge:
For i = LBound(arrTest, 1) To UBound(arrTest, 1)
arrTest2(i, 0) = arrTest(i, 1)
arrTest2(i, 1) = Mydic1(arrTest(i, 1))
Next i
Dauerts nochmal 6 Sekunden länger.
Also, das direkt im Worksheet arbeiten die schnellste Möglickeit ist, hatte ich auch noch nie.
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 11:18:25
Daniel
da hab ich auch keine Ahnung, was da intern passiert.
da müsstest du die Jungs, die das Programmiert haben, fragen warum das so ist.
uns bleibt nur, verschiedene Varianten zu testen und die beste zu verwenden.
früher wars halt so, dass die Zugriffe auf die Zellobjekte extrem langsam waren (vorallem schreibend) und es deshalb sinnvoll war, mit Arrays zu arbeiten.
Aber das schließt ja nicht aus, dass MS seine Programmierung optimiert und die Zellzugriffe beschleunigt hat, dh mit jeder Version kann sich ändern, was jetzt die beste Variante ist.
Gruß Daniel
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 11:35:50
Florian
Ok, danke für deine Hilfe.
Ich werde noch weiter testen und probieren, eventuell erreiche ich noch was.
Die Funktion wird eh nur maximal 1 mal die Woche benutzt, somit ergibt sich eine längere Kaffeepause. Gibts schlimmeres.
AW: Excel VBA | Array & Dictionary
04.09.2018 13:12:11
Rudi
Hallo,
hier kannst du noch was sparen:
            For i = 1 To UBound(arrDict)
With Mydic1
On Error Resume Next:
.Add arrDict(i, 4), arrDict(i, 1)
If Err.Number  0 Then .Item arrDict(i, 4), arrDict(i, 1)
On Error GoTo 0
End With
Next i

kürzer und wegen Wegfall der Prüfung wohl schneller
            For i = 1 To UBound(arrDict)
Mydic1(arrDict(i, 4))= arrDict(i, 1)
Next i

und hier auch:

For i = LBound(arrTest, 1) To UBound(arrTest, 1)
arrTest(i, 1) = Mydic1(arrTest(i, 4))
Next i
Gruß
Rudi
Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 22:07:27
Florian
Hi,
nach ein paar Testläufen bin ich auf folgendes gestossen.
Wenn ich beim füllen des Dictionary statt 1, 3 Stück befülle reduziert sich die Laufzeit um ~50%
Im 2. Schritt beim befüllen des 2. Arrays reduziert sich die Laufzeit auf 1/3 im Vergleich mit vorher.
Das Problem ohne die Prüfung dauert der durchlauf 10% länger. Anscheinend läuft da intern etwas wie das .exists weil wenn ich das zur Prüfung nutze dann dauerts genau so lange wie ohne.
Leider schreibt mir das auslesen der Daten aus dem Dictionary immer noch das Dictionary voll falls der key nicht existiert. (sieht man an den Items der 3 Dictionaries, weil im Step 2 wird ja eigenltich nur gelesen.)
Items:         36631
Items:         61693
Items:         112760
PUCell_Dict&Array_Step1:    00:05:13
Items:         45961
Items:         83757
Items:         130525
Step2         00:08:22 
For i = 1 To UBound(arrdict)
tmpNEID = arrdict(i, 2)
Data = arrdict(i, 1)
If Left(tmpNEID, 2) = 44 Then
On Error Resume Next:
MyDic1.Add tmpNEID, Data
If Err.Number  0 Then MyDic1.Item(tmpNEID) = Data
On Error GoTo 0
End If
If Left(tmpNEID, 2) = 54 Then
On Error Resume Next:
MyDic2.Add tmpNEID, Data
If Err.Number  0 Then MyDic2.Item(tmpNEID) = Data
On Error GoTo 0
End If
If Left(tmpNEID, 2) = 64 Then
On Error Resume Next:
MyDic3.Add tmpNEID, Data
If Err.Number  0 Then MyDic3.Item(tmpNEID) = Data
On Error GoTo 0
End If
Next i
For i = 1 To UBound(arrTest, 1)
tmpNEID = arrTest(i, 2)
If Left(tmpNEID, 2) = 44 Then arrTest(i, 1) = MyDic1(tmpNEID)
If Left(tmpNEID, 2) = 54 Then arrTest(i, 1) = MyDic2(tmpNEID)
If Left(tmpNEID, 2) = 64 Then arrTest(i, 1) = MyDic3(tmpNEID)
next i

Anzeige
AW: Excel VBA | Array & Dictionary
04.09.2018 22:39:55
Daniel
Hi
ein neues Dictionary-Element wird automatisch angelegt, sobald du das Dictionary-Element verwendest.
dh auch schon bei:
x = myDictionary("neuer Key")

wird sofort ein Dictionary-Element mit dem Key "neuer Key" angelegt.
um das zu verhindern, kannst du die Abfrage mit .Exists vorschalten:
if myDictionary.Exists("neuer Key") then
x = myDictionary("neuer Key")
else
x = ""
End if

Anzeige
AW: Excel VBA | Array & Dictionary
05.09.2018 01:05:50
Florian
wenn ich mit .exists arbeite passiert das:
Dreifach Laufzeit für Step2.
Items:         36631
Items:         61693
Items:         112760
PUCell_Dict&Array_Step1:    00:03:54
Items:         36631
Items:         61693
Items:         112760
Step2         00:24:00 

Anzeige
;

Forumthreads zu verwandten Themen

Anzeige
Anzeige
Entdecke relevante Threads

Schau dir verwandte Threads basierend auf dem aktuellen Thema an

Alle relevanten Threads mit Inhaltsvorschau entdecken
Anzeige

Infobox / Tutorial

Excel VBA: Arbeiten mit Arrays und Dictionaries


Schritt-für-Schritt-Anleitung

Um mit einem dictionary in VBA zu arbeiten und eine vba dictionary array zu nutzen, folge diesen Schritten:

  1. Daten in Arrays laden: Lade die benötigten Daten aus deinem Worksheet in ein Array, um die Verarbeitungsgeschwindigkeit zu erhöhen.

    arrDict = MSRBSCell.Range("A2:D" & MSRBSCell_end).Value2
  2. Dictionary erstellen: Erstelle ein dictionary-Objekt, um die Daten zu speichern.

    Dim Mydic1 As Object
    Set Mydic1 = CreateObject("Scripting.Dictionary")
  3. Daten ins Dictionary einfügen: Nutze eine Schleife, um die Daten in das Dictionary zu übertragen.

    For i = 1 To UBound(arrDict)
       Mydic1(arrDict(i, 4)) = arrDict(i, 1)
    Next i
  4. Daten aus dem Dictionary abrufen: Verwende das Dictionary, um die Daten für weitere Berechnungen zu holen.

    For i = LBound(arrTest, 1) To UBound(arrTest, 1)
       arrTest(i, 1) = Mydic1(arrTest(i, 4))
    Next i
  5. Daten zurückschreiben: Schreibe die bearbeiteten Daten zurück ins Worksheet.

    PUCell.Range("B2:J" & PUCell_end) = arrTest

Häufige Fehler und Lösungen

  • Lange Laufzeiten: Wenn die Ausführung deines Codes lange dauert, stelle sicher, dass du nur die benötigten Daten in dein Array lädst. Vermeide es, ganze Spalten zu lesen, wenn du nur bestimmte Zellen benötigst.

  • Fehler beim Zugriff auf nicht existierende Keys: Verwende dict.exists in deinem Code, um zu prüfen, ob ein Key im Dictionary existiert, bevor du darauf zugreifst.

    If Mydic1.Exists(tmpNEID) Then
       arrTest(i, 1) = Mydic1(tmpNEID)
    End If

Alternative Methoden

Eine effektive Methode zur Verarbeitung großer Datenmengen ist die Verwendung von Excel-Formeln anstelle von VBA-Skripten. Du kannst SVerweis oder Index und Vergleich verwenden, um Daten schnell zu verarbeiten und die Geschwindigkeit zu erhöhen.

Beispiel:

=Wenn(SVerweis(B1;MSRBSCell!B:B;1;1)=B1;Index(MSRBSCell!A:A;Vergleich(B1;MSRBSCell!B:B;1));"")

Praktische Beispiele

Wenn du mit einem vba array of dictionaries arbeitest, kann es hilfreich sein, mehrere Dictionaries zu verwenden, um die Geschwindigkeit weiter zu erhöhen. Hier ist ein Beispiel, wie du mehrere Dictionaries nutzen kannst:

Dim MyDic1 As Object, MyDic2 As Object
Set MyDic1 = CreateObject("Scripting.Dictionary")
Set MyDic2 = CreateObject("Scripting.Dictionary")

' Füllen der Dictionaries
For i = 1 To UBound(arrDict)
    If Left(arrDict(i, 4), 2) = 44 Then
        MyDic1(arrDict(i, 4)) = arrDict(i, 1)
    ElseIf Left(arrDict(i, 4), 2) = 54 Then
        MyDic2(arrDict(i, 4)) = arrDict(i, 1)
    End If
Next i

Tipps für Profis

  • Reduziere den Aufwand dict, indem du nur die wirklich benötigten Daten in dein Array lädst.
  • Vermeide das wiederholte Erstellen von Objekten in Schleifen. Erstelle sie einmal außerhalb der Schleife.
  • Nutze die With-Anweisung, um den Code übersichtlicher und schneller zu gestalten:
    With Mydic1
       .Add key, value
    End With

FAQ: Häufige Fragen

1. Wie kann ich mehrere Spalten ohne Schleife in ein Array einfügen? Du kannst mehrere Spalten direkt angeben, indem du den Bereich definierst:

arrTest = PUCell.Range("B2:E" & PUCell_end).Value2

2. Was ist der Unterschied zwischen Dictionary und Array in VBA? Ein Array ist eine Sammlung von Werten, während ein dictionary eine Sammlung von Schlüssel-Wert-Paaren ist und eine schnellere Suche ermöglicht.

3. Wie kann ich die Geschwindigkeit meines VBA-Codes verbessern? Reduziere die Anzahl der Lese- und Schreiboperationen, arbeite mehr mit Arrays und optimiere deine Schleifen.

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Entdecke mehr
Finde genau, was du suchst

Die erweiterte Suchfunktion hilft dir, gezielt die besten Antworten zu finden

Suche nach den besten Antworten
Unsere beliebtesten Threads

Entdecke unsere meistgeklickten Beiträge in der Google Suche

Top 100 Threads jetzt ansehen
Anzeige