Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1648to1652
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

MIN/MAX VBA Performance

MIN/MAX VBA Performance
28.09.2018 17:37:28
Jack
Hallo Zusammen,
hier etwas für Spezialisten.
In der folgenden Datei gibt es n Zeilen mit jeweils 4 Leveln / Titeln und einem Datum am Ende auf Level 4. Level 1-3 können mehrfach vorkommen. Ziel ist es für Level 1-3 das jeweilige Min-Max Datum von Level 4 zu evaluieren (s. Beispieldatei).
Ich habe bislang eine Formel eingesetzt z.B. "{=MIN(WENN((($J:$J=$J2));$S:$S))}". Diese ist aber leider bei der Masse an Daten inperformant. Daher habe ich es mit folgendem VBA versucht, welche auch in der Datei enthalten ist. Doch auch hier ist die Performance leider unterirdisch. Die grundsätzliche Funktionalität ist aber super.
Könnt ihr mir helfen für das Szenario eine performate Lösung zu bekommen?
Beispiel-Datei
https://www.dropbox.com/s/3c91umpbbz2hgdm/test02.xlsm?dl=0
VBA
Option Explicit
Sub Schaltfläche_Auswerten()
Dim arrDaten(), aZ As Long, larr As Long
larr = 0
'# Rechnungen
'## Titel 1 Von / Bis
With Sheets("Output")
'Range definieren
For aZ = 2 To Sheets("Output").Range("a" & Rows.Count).End(xlUp).Row
'Formel eintragen
Sheets("Output").Range("c2").FormulaArray = "=IF(RC[-2]="""",""-"",IF(MIN(IF(((C1=RC1)*(C18"""")),C18))=0,""-"",MIN(IF(((C1=RC1)*(C18"""")),C18))))"
'{=MIN(WENN((($J:$J=$J2));$S:$S))}
Sheets("Output").Range("d2").FormulaArray = "=IF(RC[-3]="""",""-"",IF(MAX(IF(C1=RC1,C19))=0, _
""-"",MAX(IF(C1=RC1,C19))))"
'{=MAX(WENN((($J:$J=$J2));$S:$S))}
'Kopieren
Sheets("Output").Range("c2:d2").Copy
Worksheets("Output").Cells(aZ, 3).Select
ActiveSheet.Paste
'Als Text einfügen
Sheets("Output").Range("c2:d2").EntireColumn.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next
End With
Sheets("Output").Range("c2:d" & larr + 1).NumberFormat = "dd.MM.yyyy" 'FormatDate
'## Titel 2 Von / Bis
With Sheets("Output")
'Range definieren
For aZ = 2 To Sheets("Output").Range("a" & Rows.Count).End(xlUp).Row
'Formel eintragen
Sheets("Output").Range("g2").FormulaArray = "=IF(RC[-2]="""","""",IF(MIN(IF(((C1=RC1)*(C18 _
"""")*(C5=RC5)),C18))=0,"""",MIN(IF(((C1=RC1)*(C18"""")*(C5=RC5)),C18))))"
Sheets("Output").Range("h2").FormulaArray = "=IF(RC[-3]="""","""",IF(MAX(IF(((C1=RC1)*(C18 _
"""")*(C5=RC5)),C19))=0,"""",MAX(IF(((C1=RC1)*(C18"""")*(C5=RC5)),C19))))"
'Kopieren
Sheets("Output").Range("g2:h2").Copy
Worksheets("Output").Cells(aZ, 7).Select
ActiveSheet.Paste
'Als Text einfügen
Sheets("Output").Range("g2:h2").EntireColumn.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next
End With
Sheets("Output").Range("g2:h" & larr + 1).NumberFormat = "dd.MM.yyyy" 'FormatDate
'## Titel 3 Von / Bis
With Sheets("Output")
'Range definieren
For aZ = 2 To Sheets("Output").Range("a" & Rows.Count).End(xlUp).Row
'Formel eintragen
Sheets("Output").Range("k2").FormulaArray = "=IF(RC[-2]="""","""",IF(MIN(IF(((C1=RC1)*(C18 _
"""")*(C5=RC5)*(C9=RC9)),C18))=0,"""",MIN(IF(((C1=RC1)*(C18"""")*(C5=RC5)*(C9=RC9)),C18))))"
Sheets("Output").Range("l2").FormulaArray = "=IF(RC[-3]="""","""",IF(MAX(IF(((C1=RC1)*(C18 _
"""")*(C5=RC5)*(C9=RC9)),C19))=0,"""",MAX(IF(((C1=RC1)*(C18"""")*(C5=RC5)*(C9=RC9)),C19))))"
'Kopieren
Sheets("Output").Range("k2:l2").Copy
Worksheets("Output").Cells(aZ, 11).Select
ActiveSheet.Paste
'Als Text einfügen
Sheets("Output").Range("k2:l2").EntireColumn.Select
Selection.Copy
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next
End With
Sheets("Output").Range("k2:l" & larr + 1).NumberFormat = "dd.MM.yyyy" 'FormatDate
End Sub

Danke &
beste Grüße,
Jack

13
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: MIN/MAX VBA Performance
28.09.2018 17:56:11
Daniel
HI
naja, für die Berechnungszeit einer Formel ist es egal, ob du die von Hand erstellt hast oder per VBA.
das Problem ist, dass in Matrixformeln immer alle angegebenen Zellen durchgerechnet werden, ohne dass ein Abgleich mit dem Tatsächlich genutzten Zellbereich stattfindet so wie in einer normalen Formel.
dh wenn in der Tabelle die Zellen A1-A100 gefüllt sind, rechnet ein =Min(A:A) nur diese 100 Zellen durch. Bei {=Min(A:A*1)} werden jedoch alle 1,04 Millionen Zellen berechnet und das dauert halt.
der Vorteil bei VBA wäre halt, dass den tatsächlich verwendeten Zellbereich ermitteln und in die Formeln einfügen kannst.
ich mach das in solchen Fällen so, dass ich die Formel zunächst einmal in eine Variable schreibe und dabei an der Stelle, an der die Zeilennummer eingefügt werden soll, einen Dummy-Text hinschreibe (z.B. "zzz") dann wird per Replace der Dummy-Text durch die Zeilennummer ersetzt, bevor die Formel in die Zelle kommt:
hier mal als gekürztes Beispiel für die Spalten C1 und C18, das müsstet du dann entsprechen in deinen Code einbauen:
dim FO as string
dim LZ as Long
LZ = Sheets("Output").Cells(Rows.count, 1).end(xlup).Row
FO =  "=MIN(IF(((R1C1:RzzzC1=RC1)*(R1C18:RzzzC18,"""")),R1C18:RzzzC18))))"
FO = Replace(FO,"zzz", LZ)
Range(...).FormulaArray = FO
Gruß Daniel
Anzeige
AW: MIN/MAX VBA Performance
28.09.2018 19:16:07
Jack
Danke für das Feedback,
leider verstehe ich mit meinem aktuellen VBA Stand noch nicht wie du das in die bestehnde Formel einbauen würdest.
Kannst du mir da ein kurzes Beispiell zeigen?
Option Explicit
Sub Schaltfläche_Auswerten()
Dim arrDaten(), aZ As Long, larr As Long
larr = 0
'# Rechnungen
'## Titel 1 Von / Bis
Dim FO As String
Dim LZ As Long
LZ = Sheets("Output").Cells(Rows.Count, 1).End(xlUp).Row
FO = "=MIN(IF(((R1C1:RzzzC1=RC1)*(R1C18:RzzzC18,"""")),R1C18:RzzzC18))))"
FO = Replace(FO, "zzz", LZ)
Range("c2:d").FormulaArray = FO
'## Titel 2 Von / Bis
'## Titel 3 Von / Bis
End Sub

Anzeige
AW: MIN/MAX VBA Performance
28.09.2018 21:05:07
Daniel
zwar ein einem sehr kurzen Beispiel aber das Prinzip sollte erkennbar sein:
- du darfst in den Array-Formlen keine ganzen Spalten angeben (A:A / C1) sondern musst immer den Zellbereich so exakt wie möglich beschreiben ($A$1:$A$99 / R1C1:R99C1)
- wenn du die Zellbereiche nicht fest vorgeben sondern passend zur Datei ermitteln willst, musst du die letzte Zeilennummer in eine Variable schreiben und diese dann in die Formeln einbringen.
damit das Übersichlicher wird, macht man das so wie von mir im Beispiel beschrieben über den Trick mit Replace und dem Dummytext. das ist übersichtlicher, als den Formeltext zu trennen und die Variable einzufügen.
auch wieder ein einfaches Bespiel:
unbersichtlich:
LZ = 99
.Formular1C1 = "=R1C1:R" & LZ & "C1"
übersichtlicher

LZ = 99
FO = "=R1C1:RzzzC1"
FO = Replace(FO, zzz, LZ)
.FormulaR1C1 = FO
Gruß Daniel
Anzeige
@Daniel: MIN/MAX VBA Performance
30.09.2018 10:46:35
Jack
Hallo,
habe es versucht aber leider will es nicht so recht.
Mit dem VBA kommt ein Fehler raus
Sub e()
Dim FO As String
Dim LZ As Long
LZ = 99
FO = "=MAX(C[zzz])"
FO = Replace(FO, zzz, LZ)
'Sheets("Output").Range("K2").Formula = "=MAX(C[8])"
Sheets("Output").Range("K2").Formula = FO
End Sub

und mit der Formel
Sub e()
Dim FO As String
Dim LZ As Long
LZ = 99
FO = "=MAX(Czzz)"
FO = Replace(FO, zzz, LZ)
'Sheets("Output").Range("K2").Formula = "=MAX(C[8])"
Sheets("Output").Range("K2").Formula = FO
End Sub
schreibt er einfach nur "=MAX(Czzz)" in die Zelle
Beste Grüße,
Jack
Anzeige
AW: @Daniel: MIN/MAX VBA Performance
30.09.2018 11:02:42
Daniel
HI
naja der Fehler ist, dass im Replace das zzz ein fester Text ist und keine Variable:
also:
FO = Replace(FO, "zzz", LZ)
aber du solltest dir nochmal genauer durchlesen, was ich dir geschrieben habe, so wie du das umgesetzt hast, hast du das was ich dir sagen wollte, noch nicht richtig verstanden.
Gruß Daniel
AW: @Daniel: MIN/MAX VBA Performance
30.09.2018 16:50:58
Jack
Danke, hatte ich dann auch gesehen. Manchmal sind es die kleinen Dinge.
Ja das war noch auf experimenteller Ebene. Läuft jetzt schon deutlich schneller. Bin aktuell auf folgendem Stand, aber mit der Formel erhöht sich meine Performance trotzdem noch von 4 auf 20 Sekunden. Also noch nicht optimal.. Ist der aktuelle Stand den deiner Beschreibung konform? Habe es danach versucht umzusetzen, also keine ganzen Spalten (A:A) mehr enthalten.
Sub Test
'## Titel - Parameter
Dim LZ As Long
LZ = Sheets("Output").Range("A" & Rows.Count).End(xlUp).Row
For aZ = 2 To Sheets("Output").Range("A" & Rows.Count).End(xlUp).Row
'## Titel 1 Von / Bis
'Formel
Dim T1v As String
T1v = "=IF(Output!A2="""",""-"",IF(MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$R$2:$R$ _
zzz"""")),Output!$R$2:$R$zzz))=0,""-"",MIN(IF(((Output!$A$2:$A$zzz=A2)*(Output!$R$2:$R$zzz"""")),Output!$R$2:$R$zzz))))"
T1v = Replace(T1v, "zzz", LZ)
Sheets("Output").Cells(2, 3).FormulaArray = T1v
Dim T1b As String
T1b = "=IF(Output!A2="""",""-"",IF(max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$ _
zzz"""")),Output!$s$2:$s$zzz))=0,""-"",max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$zzz))))"
T1b = Replace(T1b, "zzz", LZ)
Sheets("Output").Cells(2, 4).FormulaArray = T1b
'Kopieren
Sheets("Output").Range("C2:D2").Copy
Sheets("Output").Range("C3:D" & LZ).PasteSpecial
'Als Text einfügen
Sheets("Output").Range("C3:D" & LZ).Copy
Sheets("Output").Range("C3:D" & LZ).PasteSpecial Paste:=xlPasteValues, operation:=xlNone,  _
skipblanks _
:=False, Transpose:=False
'Zelle formatieren als Datum
Sheets("Output").Range("c2:d" & larr + 1).NumberFormat = "dd.MM.yyyy" 'FormatDate
End Sub

Anzeige
AW: @Daniel: MIN/MAX VBA Performance
01.10.2018 10:41:25
Daniel
Hi
ja, ist schon so wie ich mir das gedacht habe.
Matrxiformeln brauchen halt Rechenzeit.
Wenn du hinterher sowieso die Formeln durch ihre Werte ersetzt, dann wäre es natürlich auch kein Problem, mit temporären Hilfsspalten für Zwischenrechnungen zu arbeiten, die Hilfsspalten kannst du ja am Ende wieder löschen. Ist natürlich nur dann sinnvoll, wenn die Hilfsspalten dazu geeignet sind, die Rechenlast zu reduzieren.
eine andere Methode für solche Auswertungen in VBA wäre u.U. auch das Dictionary-Objekt.
um dir genaueres sagen zu ´können, solltest du eine Beispieldatei mit den Daten und deinem Wunschergebnis hochladen und nochmal genau beschreiben, was berechnet werden soll.
ich bin grad zu faul, um das aus deinen Formeln "rückzuübersetzen"
Gruß Daniel
Anzeige
AW: @Daniel: MIN/MAX VBA Performance
01.10.2018 16:53:13
Jack
Hallo Daniel,
danke für die Analyse, ich habe mal folgende Datei mit dem gewünschten Szenario bereitgestellt:
https://www.dropbox.com/s/4vboi3gn3hllzfv/test02b.xlsm?dl=0
In diesem Fall braucht das VBA ca. 9 Sekunden. In meiner Original Datei mit sonstigen VBAs rechnet der 20 Sekunden lang. Ich habe in der o.g. Datei aber mal nur den Rechen-intensivsten Teil extrahiert, da es sonst etwas viel wird.
In wiefern mir hier Hilfsspalten helfen würden kann ich nicht bewerten & mit einem Dictionary-Objekt kenn ich mich noch nicht aus.
Das Szenario ist - Ich habe eine Tabelle von Daten. Jede Zeile hat vier mögliche Titel Level (1-4). Die Titel Level 2 und 3 sind optional. Die Titel Level 1-3 können in der Tabelle mehrfach vorkommen. Das Titel Level 4 gibt es immer nur einmalig. Die Titel Level 1-4 bilden quasi eine hierarchische Struktur ab.
Zu Level 4 gibt es immer noch weitere Informationen - hier ein Von und Bis Datum.
Für die Titel Level 1, 2 und 3, welche mehrfach auftauchen können, soll nun das jeweilige Min (von) und Max (bis) berechnet werden. Wenn es zu Titel Level 1 also vier Zeilen/Einträge gibt, wird von diesen der entsprechende Min/Max Wert des Von/Bis Datums von Level 4 gezogen.
Leider funktioniert das meines Kenntnisstandes nur mit einer Formel als Array, aufgrund der aufgeführten Bedingung z.B. einfach für das Titel 1 Von Datum {=MIN(WENN((($A:$A=$J2));$R:$R))}. Eine VBA Alternative habe ich nicht gefunden. In der VBA der Datei sind noch weitere Bedingungen mit angegeben. Die o.g. Formel ist aber die Basis des Ganzen.
Berechnet werden hier die gelb markierten Spalten, die schwarzen werden hier als gegeben angesehen.
Vielen Dank für die Unterstützung & Analyse! Sollten noch Infos fehlen, gerne kurz Bescheid sagen!
Beste Grüße,
Jack
Hier nochmal das VBA
Sub e()
'----------------------------------------------------------------------------------------------- _
'----------------------------------------------------------------------------------------------- _
'# Zeilen leeren
Sheets("Output").Range("C2:D100").ClearContents
Sheets("Output").Range("G2:H100").ClearContents
Sheets("Output").Range("K2:L100").ClearContents
'----------------------------------------------------------------------------------------------- _
'----------------------------------------------------------------------------------------------- _
'# Allgemeine Parameter
Dim arrDaten(), aZ As Long, larr As Long
Dim Level1Titel As String, Level2Titel As String, Level3Titel As String
Dim Level1Beschr As String, Level2Beschr As String, Level3Beschr As String
larr = 0
'----------------------------------------------------------------------------------------------- _
'----------------------------------------------------------------------------------------------- _
'# Rechnungen
'## Titel - Parameter
Dim LZ As Long
LZ = Sheets("Output").Range("A" & Rows.Count).End(xlUp).Row
For aZ = 2 To Sheets("Output").Range("A" & Rows.Count).End(xlUp).Row
'## Titel 1 Von / Bis
'Formel Von - Berechnet das Minimal Datum für den jeweiligen Titel
Dim T1v As String
T1v = "=IF(Output!A2="""",""-"",MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$R$2:$R$zzz _
"""")),Output!$R$2:$R$zzz)))"
'T1v = "=IF(Output!A2="""",""-"",IF(MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$R$2:$R$ _
zzz"""")),Output!$R$2:$R$zzz))=0,""-"",MIN(IF(((Output!$A$2:$A$zzz=A2)*(Output!$R$2:$R$zzz"""")),Output!$R$2:$R$zzz))))"
T1v = Replace(T1v, "zzz", LZ)
Sheets("Output").Cells(2, 3).FormulaArray = T1v
'Formel Bis - Berechnet das Maximal Datum für den jeweiligen Titel
Dim T1b As String
T1b = "=max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$ _
zzz))"
'T1b = "=IF(Output!A2="""",""-"",IF(max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$ _
zzz"""")),Output!$s$2:$s$zzz))=0,""-"",max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$zzz))))"
T1b = Replace(T1b, "zzz", LZ)
Sheets("Output").Cells(2, 4).FormulaArray = T1b
'ArrayFormel in Zeile 2 für die weiteren Zeilen kopieren
Sheets("Output").Range("C2:D2").Copy
Sheets("Output").Range("C3:D" & LZ).PasteSpecial
'Berechnete Formeln in Spalte als Text einfügen
Sheets("Output").Range("C3:D" & LZ).Copy
Sheets("Output").Range("C3:D" & LZ).PasteSpecial Paste:=xlPasteValues, operation:=xlNone,  _
skipblanks _
:=False, Transpose:=False
'## Titel 2 Von / Bis
'Formel Von
Dim T2v As String
T2v = "=IF(Output!e2="""",""-"",MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$e$2:$e$zzz= _
Output!e2)*(Output!$R$2:$R$zzz"""")),Output!$R$2:$R$zzz)))"
'T2v = "=IF(Output!e2="""",""-"",IF(MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$e$2:$e$ _
zzz=Output!e2)*(Output!$R$2:$R$zzz"""")),Output!$R$2:$R$zzz))=0,""-"",MIN(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$R$2:$R$zzz"""")),Output!$R$2:$R$zzz))))"
T2v = Replace(T2v, "zzz", LZ)
Sheets("Output").Cells(2, 7).FormulaArray = T2v
'Formel Bis
Dim T2b As String
T2b = "=IF(Output!e2="""",""-"",max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$E$2:$E$zzz= _
Output!E2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$zzz)))"
'T2b = "=IF(Output!e2="""",""-"",IF(max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$E$2:$E$ _
zzz=Output!E2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$zzz))=0,""-"",max(IF(((Output!$A$2:$A$zzz=Output!A2)*(Output!$s$2:$s$zzz"""")),Output!$s$2:$s$zzz))))"
T2b = Replace(T2b, "zzz", LZ)
Sheets("Output").Cells(2, 8).FormulaArray = T2b
'Kopieren
Sheets("Output").Range("g2:h2").Copy
Sheets("Output").Range("g3:h" & LZ).PasteSpecial
'Als Text einfügen
Sheets("Output").Range("g3:h" & LZ).Copy
Sheets("Output").Range("g3:h" & LZ).PasteSpecial Paste:=xlPasteValues, operation:=xlNone,  _
skipblanks _
:=False, Transpose:=False
'## Titel 3 Von / Bis
'Formel Von
Dim T3v As String
'T3v = "=MIN(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($R$2:$R$zzz"""")),$R$ _
2:$R$zzz))"
T3v = "=IF(i2="""",""-"",MIN(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($R$2:$ _
R$zzz"""")),$R$2:$R$zzz)))"
'T3v = "=IF(i2="""",""-"",IF(MIN(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($R$ _
2:$R$zzz"""")),$R$2:$R$zzz))=0,""-"",MIN(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($R$2:$R$zzz"""")),$R$2:$R$zzz))))"
T3v = Replace(T3v, "zzz", LZ)
Sheets("Output").Cells(2, 11).FormulaArray = T3v
'Formel Bis
Dim T3b As String
T3b = "=IF(i2="""",""-"",max(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($s$2:$ _
s$zzz"""")),$s$2:$s$zzz)))"
'T3b = "=IF(i2="""",""-"",IF(max(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($s$ _
2:$s$zzz"""")),$s$2:$s$zzz))=0,""-"",max(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($s$2:$s$zzz"""")),$s$2:$s$zzz))))"
T3b = Replace(T3b, "zzz", LZ)
Sheets("Output").Cells(2, 12).FormulaArray = T3b
'Kopieren
Sheets("Output").Range("k2:l2").Copy
Sheets("Output").Range("k3:l" & LZ).PasteSpecial
'Als Text einfügen
Sheets("Output").Range("k3:l" & LZ).Copy
Sheets("Output").Range("k3:l" & LZ).PasteSpecial Paste:=xlPasteValues, operation:=xlNone,  _
skipblanks _
:=False, Transpose:=False
'----------------------------------------------------------------------------------------------- _
Next
'----------------------------------------------------------------------------------------------- _
'----------------------------------------------------------------------------------------------- _
End Sub

Anzeige
AW: @Daniel: MIN/MAX VBA Performance
02.10.2018 10:02:08
daniel
Hi
kleiner Optiomierungsansatz:
1. Liste nach Titel sortieren
2. die Formeln für Min- und Max nach folgenden Schema erweitern:
=Wenn(Titel = Titel eine Zeile höher;Wert eine Zeile höher; MIN( neuberechnung des Min-Wertes)
das reduziert die Rechenlast, weil du die Aufwendige Matrixberechnung dann nur beim ersten Auftreten des Titels ausführst und bei weiteren Auftreten nur den Wert aus der Vorgängerzelle übernimmst.
Gruß Daniel
AW: @Daniel: MIN/MAX VBA Performance
02.10.2018 13:35:56
Jack
Danke für den Tipp,
das bringt mir ca 2 Sekunden +. Aber da muss ich leider noch mehr raus holen. Schade, dass es für das Min/Max kein direktes VBA gibt.
By the way - hast du Erfahrung damit, dass er einen Error ausgibt, wenn die einzutragenden Formeln zu lang werden?
T3v = "=IF(i2="""",""-"",MIN(IF((($A$2:$A$zzz=A2)*($E$2:$E$zzz=E2)*($i$2:$i$zzz=i2)*($R$2:$  _
_
R$zzz"""")),$R$2:$R$zzz)))" 

=> Sobald ich da 1 Bedingung mehr hinzufüge gibt er mir einen Error raus,nehme ich dafür eine andere Bedingung raus, klappt es wieder..
Anzeige
AW: @Daniel: MIN/MAX VBA Performance
02.10.2018 15:07:36
Jack
Habe übrigens festgestellt,
dass nicht die Formel wirklich die Performance frisst, sondern die 2 Kopier-Aktionen formel kopieren + als text einfügen gleichermaßen. Sobald auch nur das Kopieren & Text einfügen weg genommen wird, wird es deutlich besser
'## Titel 3 Von / Bis
'(1.1)Formel Von
Dim T3v As String
T3v = "=IF(i2="""",""-"",if(i1=i2,k1,MIN(IF((($u$2:$u$zzz=u2)*($R$2:$R$zzz"""")),$R$2:$R$zzz))))"
T3v = Replace(T3v, "zzz", LZ)
Sheets("Output").Cells(2, 11).FormulaArray = T3v
'(1.2) Formel Bis
Dim T3b As String
T3b = "=IF(i2="""",""-"",if(i1=i2,l1,max(IF((($u$2:$u$zzz=u2)*($s$2:$s$zzz"""")),$s$2:$s$zzz))))"
T3b = Replace(T3b, "zzz", LZ)
Sheets("Output").Cells(2, 12).FormulaArray = T3b
'(2) Kopieren
Sheets("Output").Range("k2:l2").Copy
Sheets("Output").Range("k3:l" & LZ).PasteSpecial
'(3) Als Text einfügen
Sheets("Output").Range("k3:l" & LZ).Copy
Sheets("Output").Range("k3:l" & LZ).PasteSpecial Paste:=xlPasteValues, operation:=xlNone, skipblanks _
:=False, Transpose:=False
Die Frage ist also ob man etwas einfaches für 2 & 3 finden kann
Anzeige
AW: @Daniel: MIN/MAX VBA Performance
02.10.2018 15:39:25
Daniel
Hi
die Formeln, die per VBA in die Zellen geschrieben werden, müssen deutlich kürzer sein als von Hand geschriebene Formeln.
bei FormulaArray meines wissens nach sehr knappe 256 zeichen, für normale Formeln c.a. 1000 zeichen, von Hand geschriebene dürfen 4000 Zeichen lang sein...
für normale Formeln gibt's nen Workaround, wie man diese Grenze umgehen kann, der funktoniert aber nicht mit Matrixformeln.
nächste Möglichkeit wäre ggf, die Funktion AGGREGAT(14;6;...1) anstelle von MAX und AGGREGAT(14;6;...;1) anstelle von MIN zu verwenden. Anwendungsbeispiele sollten sich genügend im Internet finden.
das Aggregat soll hier angeblich schneller sein.
Weiter Vorteil von Aggregat ist, dass es hier quasi eine automatische Matrixformeln ist.
dh du kannst im Mittelteil von Aggregat Matrixformelberechnungen durchführen, trotzdem wird die Formel aber wie eine normale Formel behandelt und kann auch mit .Formula oder .FormulaR1C1 in die Zellen geschrieben werden, womit dann wieder die Beschränkung in der maximalen Formellänge größer ausfällt.
Aggregat funktioniert so, dass du den zu verwendenen BasisWert durch die Bedingungen teilst.
in einer Berechnung wird eine Bedingung (WAHR oder FALSCH) wie 1 oder 0 gewertet, durch die Division entsteht ein Fehler und mit dem zweiten Parameter 6 weist du die Aggregatfunition an, Fehler zu ignorieren.
dh statt:

MIN(IF((($u$2:$u$zzz=u2)*($R$2:$R$zzz"""")),$R$2:$R$zzz))

dann:

Aggregate(15,6,$R2$:$R$zzz/(($U$2:$U$zzz=$U$2)*($R$2:$R$zzz"""")),1)
andere Möglichkeit das ganze zu beschleunigen:
du sortierst nach den Titelen und ermittelst in der Formel dann den Zellbereich in dem diese Titel stehen. Dann kannst du das MIN/Max gezielt auf diesen Zellbereich anwenden und brauchst keine Matrixformle mehr. Leerzellen in Spalte R werden dann auch ignoriert:
Gruß Daniel
Dictionary ist in vielen Fällen der Problemlöser
02.10.2018 16:31:42
Daniel
Prinzipell bietet sich hier auch eine reine VBA-Lösung an, in welcher man in einem Dictionary-Objekt zu jedem Titel den Min- und Max-wert sammelt.
das hat gegenüber der Formel, dass man das Gesamtergbnis mit EINEM Schleifendurchlauf über alle Zeilen ermitteln kann.
Bei deiner Formellösung ist jede Formel autarkt, dh jede Formel enthält eine Schleife über alle Zeilen, was den Rechenaufwand natürlich im Quadrat steigen lässt:
getestet und passend für deine Beispieldatei
Sub MinMaxDatum()
Dim arrTitel1, T As String
Dim arrErg
Dim arrDatum
Dim z As Long
Dim dicMin As Object
Dim dicMax As Object
Dim SP
With Sheets("Output").UsedRange
arrDatum = .Columns(18).Resize(, 2).Value
For Each SP In Array(1, 5, 9)
Set dicMin = CreateObject("Scripting.Dictionary")
Set dicMax = CreateObject("Scripting.Dictionary")
With .Columns(SP)
arrTitel1 = .Value
arrErg = .Offset(0, 2).Resize(, 2).Value
For z = 2 To UBound(arrTitel1, 1)
T = arrTitel1(z, 1)
If arrTitel1(z, 1)  "" Then
If arrDatum(z, 1)  "" Then
If dicMin.Exists(T) Then
If arrDatum(z, 1)  "" Then
If dicMax.Exists(T) Then
If arrDatum(z, 2) > dicMax(T) Then dicMax(T) = arrDatum(z, 2)
Else
dicMax(T) = arrDatum(z, 2)
End If
End If
End If
Next z
For z = 2 To UBound(arrTitel1, 1)
T = arrTitel1(z, 1)
arrErg(z, 1) = "-"
arrErg(z, 2) = "-"
If T  "" Then
If dicMin.Exists(T) Then arrErg(z, 1) = dicMin(T)
If dicMax.Exists(T) Then arrErg(z, 2) = dicMax(T)
End If
Next z
.Offset(0, 2).Resize(, 2).Value = arrErg
End With
Next SP
End With
End Sub
Gruß Daniel

272 Forumthreads zu ähnlichen Themen

Anzeige
Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige