Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1640to1644
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

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

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
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
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ß.
Anzeige
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
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
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.
Anzeige
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

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 

49 Forumthreads zu ähnlichen Themen

Anzeige
Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige