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

Zählenwenn in mehreren Ranges Highspeed

Zählenwenn in mehreren Ranges Highspeed
Jan
Hallo,
Ich muss in mehreren Bereichen überprüfen, ob eine der Zellen in den Bereichen einen Wert enthält. Da die Excelfunktion "Zählenwenn" nur einen Bereich unterstützt, habe ich mir folgende Funktion in VBA geschrieben.

Function ZÄHLE(Wert As String, ParamArray Rng() As Variant) As Integer
Dim Bereich As Variant
Dim Zelle As Range
For Each Bereich In Rng
For Each Zelle In Bereich
If Zelle.Value = Wert Then
ZÄHLE = ZÄHLE + 1
End If
Next Zelle
Next Bereich
End Function
Ich Zähle in vier Bereichen über insgesamt 20.000 Werte. Warum ist die Excelfunktion "Zählenwenn" so viel schneller als meine Funktion? Wie kann ich meine Funktion beschleunigen?
Gruß
Jan
AW: Zählenwenn in mehreren Ranges Highspeed
03.10.2009 14:08:20
Jan
Schön, wenn man eine Minute später auf seine eigene Frage reagiert.
Ich habe bereits eine zweite Möglichkeit gefunden, die wesentlich schneller ist. Da frag ich mich doch, was Excel bei Zählenwenn schneller macht. Hier meine schnellere Variante:
Function ZÄHLER(Wert As String, ParamArray Rng() As Variant) As Integer
Dim Bereich As Variant
For Each Bereich In Rng
ZÄHLER = ZÄHLER + Application.WorksheetFunction.CountIf(Bereich, Wert)
Next Bereich
End Function
Vielleicht bekommt es ja einer noch schneller hin.
Gruß
Jan
AW: Zählenwenn in mehreren Ranges Highspeed
03.10.2009 14:45:03
Nepumuk
Hallo,
weil die Originalfunktion in C++ geschrieben ist. Das ist um einiges schneller als VBA, da in C die Speicherverwaltung effizienter ist. Dafür ist die Sprache aber wesentlich weniger tolerant gegenüber unsauberer Programmierung.
Du machst den Fehler die Zelle in den Bereichen anzusprechen. Schau dir mal an, wie viele Eigenschaften eine Zelle hat. Alle diese Eigenschaften werden, wenn du die Zelle ansprichst, in den Arbeitsspeicher geladen. Also jedes Mal ein paar 1.000 Byte.
Da dich aber nur die Value-Eigenschaft interessiert ist es besser diese erst in ein Array zu schreiben und diese Array abzuarbeiten. So ein einzelner Eintrag im Array hat je nach Zellinhalt zwischen 16 und ein paar 100 Bytes. Damit ist das ganze wesentlich schneller. Auf meinem Rechner, bei 20.000 Zellen maximal 0,01 Sekunde.
Beispiel:
Public Function ZÄHLE_SCHNELL(Wert As String, ParamArray Rng() As Variant) As Double
    Dim Bereich As Variant
    Dim Werte_Array As Variant, Einzelwert As Variant
    
    For Each Bereich In Rng
        Werte_Array = Bereich.Value2
        For Each Einzelwert In Werte_Array
            If Einzelwert = Wert Then ZÄHLE_SCHNELL = ZÄHLE_SCHNELL + 1
        Next Einzelwert
    Next Bereich
    
End Function

Gruß
Nepumuk
Anzeige
@Nepumuk sehr intersand, ...
03.10.2009 15:13:05
Tino
Hallo Nepumuk,
aber warum ist der Geschwindigkeitsunterschied nur bei Value2 und nicht auch bei Value.
Value2 gibt doch eigentlich nur den Tatsächlichen Wert der Zelle zurück also ohne Format.
z. Bsp. bei einem Datum wird der Wert nicht als Date sondern als Double zurückgegeben.
Gruß Tino
AW: @Nepumuk sehr intersand, ...
03.10.2009 15:54:39
Nepumuk
Hallo Tino,
ob Value oder Value2 ist eigentlich egal wenn nach einem String gesucht wird. Geschwindigkeitsunterschiede konnte ich dabei nicht wirklich messen.
Gruß
Nepumuk
habe es mal so getestet.
03.10.2009 16:18:54
Tino
Hallo,
ich habe zwar nicht mit String sondern mit Zahlen (Double) getestet.
Neue Datei alle Zellen auf Standard.
Bei mir kommt raus, dass Value2 doppelt so schnell.
Bei 65536 Zeilen (xl2007 Kompatibilitätsmodus)
Value2 = 0,0625 Sekunden
Value = 0,125 Sekunden
kommt als Code in Modul1
Option Explicit 
 
Sub Tabelle_Mit_Daten_Fuehr_Test_fuellen() 
 Columns("A:E").Formula = "=ROW()" 'alle Zellen mit einer Zahl füllen 
End Sub 
 
Sub Test1_Value() 
Dim sTime As Single 
Dim A As Long, B As Long, Erg As Long 
Dim meAr As Variant 
Dim SuchWert As Double 
 
sTime = Timer 
 
    SuchWert = 10 
    meAr = Range("A:E").Value 
     
    For A = 1 To Ubound(meAr) 
     For B = 1 To Ubound(meAr, 2) 
      If meAr(A, B) = SuchWert Then Erg = Erg + 1 
     Next B 
    Next A 
 
Debug.Print Erg, Timer - sTime 
 
End Sub 
 
Sub Test2_Value2() 
Dim sTime As Single 
Dim A As Long, B As Long 
Dim meAr As Variant, Erg As Long 
Dim SuchWert As Double 
 
sTime = Timer 
 
    SuchWert = 10 
    meAr = Range("A:E").Value2 
     
    For A = 1 To Ubound(meAr) 
     For B = 1 To Ubound(meAr, 2) 
      If meAr(A, B) = SuchWert Then Erg = Erg + 1 
     Next B 
    Next A 
 
Debug.Print Erg, Timer - sTime 
 
End Sub 
 
 

Gruß Tino
Anzeige
AW: habe es mal so getestet.
03.10.2009 18:24:40
Nepumuk
Hallo Tino,
der Unterschied liegt in der Zuweisung der Werte an das Array. Value2 ist von Haus aus ein Array (siehst du im Lokalfenster) und benötigt nur 0,6 Sekunden, Value muss dagegen erst mal ein Array im Speicher aufbauen und benötigt daher 2,2 Sekunden (Excel 2007 mit 1.048.576 Zeilen). Bei den 20.000 Werten aus dem 1. Test spielt das noch keine große Rolle, aber bei 5.242.880 Zellen merkt man das.
Gruß
Nepumuk
danke für die Aufklärung oT.
03.10.2009 20:32:37
Tino
Hi Tino, was zumTeufel ist "intersand"? 'Ne...
03.10.2009 19:02:20
Luc:-?
...Baumaterial-Außenhandelsfirma würde ich meinen... ;-)
Gruß+schöFTWE, Luc :-?
ich finde es schon mal interessant...
03.10.2009 20:31:03
Tino
Hallo,
ein Array zuvor mit Value2 zu füllen und dadurch fast doppelt so schnell zu sein.
Millionen Beiträge hier im Forum arbeiten eben immer nur mit dem Value,
habe selbst noch keinen gesehen der in diesem Zusammenhang Value2 benutzt hat oder hätte (mich eingeschlossen).
Gruß Tino
Anzeige
...das ist unbestreitbar! Und da wurde noch...
03.10.2009 22:03:05
Luc:-?
...vor ca 1-3 Jahren hier über Schnelligkeitsdifferenzen zwischen mit und ohne .Value (als Standardeigenschaft von Range — von .Value2 war damals nicht die Rede!) spekuliert...
Das wäre dann ja hiermit, wenn auch erst im Nachhinein, erledigt...
Gruß Luc :-?
Obwohl es auch einen Nachteil gibt,...
09.10.2009 05:16:22
Luc:-?
...Tino...
Default-Eigenschaft von Range ist .Value; man kann das also auch weglassen und somit auch andere Felder wie Matrixkonstanten und Ergebnisse von Fml-Ausdrücken (Terme) laden, wenn das zugehörige Argument einer udF entsprechend deklariert wurde (ohne As-Zusatz als Variant).
Wenn man auch in diesem Falle mit .Value2 arbeiten will, muss man die unterschiedl Fälle identifizieren. Deshalb verwende ich hier zZ lieber ...Transpose(...Transpose(...)).
Gruß Luc :-?
Anzeige
bei mir in der Hilfe steht...
03.10.2009 15:34:21
Tino
Hallo,
Range.Value2-Eigenschaft
Der einzige Unterschied zwischen dieser Eigenschaft und der Value-Eigenschaft besteht darin,
dass die Value2-Eigenschaft die Datentypen Currency und Date nicht verwendet.
Sie können auf Werte, die mit diesen Datentypen formatiert sind, als Gleitkommazahlen zugreifen,
indem Sie den Datentyp Double verwenden.

Was macht nun diesen Unterschied aus?
Gruß Tino
AW: bei mir in der Hilfe steht...
03.10.2009 15:56:14
Nepumuk
Hi,
unformatierte Zahlen benötigen weniger Speicher.
Gruß
Nepumuk
AW: Zählenwenn in mehreren Ranges Highspeed
03.10.2009 16:50:29
Jan
Und wieder was dazu gelernt. Ich liebe dieses Forum.
Ich hab alle Varianten getestet. Meine erste Variante ist 6 mal langsamer als die Variante von Nepumuk. Diese ist wiederum 10 mal langsamer als meine zweite Variante. (getestet an 13Mio. Werten in 12 Bereichen)
Gruß
Jan
Anzeige

315 Forumthreads zu ähnlichen Themen

Anzeige
Anzeige
Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige

Beliebteste Forumthreads (12 Monate)

Anzeige
Anzeige
Anzeige