Diskussion zum Artikel "Das MQL5-Kochbuch: Implementierung eines Assoziativen Arrays oder eines Lexikons für raschen Datenzugriff"

 

Neuer Artikel Das MQL5-Kochbuch: Implementierung eines Assoziativen Arrays oder eines Lexikons für raschen Datenzugriff :

Dieser Beitrag beschreibt einen speziellen Algorithmus mit dem auf Elemente mittels ihrer einmaligen Schlüssel zugegriffen werden kann. Als Schlüssel kann jeder einfache Datentyp verwendet werden. Er kann z.B. als String oder eine ganzzahlige Variable dargestellt werden. So einen Datenbehälter kennt man meistens als Lexikon oder ein assoziatives Array. Er bietet einen leichteren und effizienteren Weg der Problemlösung.

Wenn wir uns in der Größe unseres arrayObj Arrays verrechnen oder es mittels eines falschen Index adressieren, führt das zu einem schwerwiegenden Fehler in unserem Programm. Doch dieser Code genügt für diesen Beitrag zur Veranschaulichung.

Stellen wir diese Elemente schematisch dar:


Abb. 1 Schema der Datenspeicherung im Zeiger-Array

Autor: Vasiliy Sokolov

 

Tolle Arbeit, Hut ab vor dem Autor! Das ist etwas, das MQ schon vor langer Zeit in \MQL5\Include\Arrays hätte aufnehmen sollen, ich hoffe, es wird in den nächsten Versionen in die Bibliothek aufgenommen. Übrigens funktioniert auch in MQL4 alles einwandfrei, hier sind die Messungen aus dem ersten Test. Ich verstehe, dass es nicht möglich ist, einfache Datentypen anstelle von *CObject einzubinden, weil es keine vollwertigen Zeiger gibt? Oder gibt es eine Möglichkeit, dies zu umgehen?

2015.03.23 13:25:54.617 TestDict EURUSD,M1: 1000000 elements. Add: 1373; Get: 218
2015.03.23 13:25:52.644 TestDict EURUSD,M1: 950000 elements. Add: 1216; Get: 219
2015.03.23 13:25:50.833 TestDict EURUSD,M1: 900000 elements. Add: 1217; Get: 218
2015.03.23 13:25:49.069 TestDict EURUSD,M1: 850000 elements. Add: 1154; Get: 187
2015.03.23 13:25:47.424 TestDict EURUSD,M1: 800000 elements. Add: 1092; Get: 187
2015.03.23 13:25:45.844 TestDict EURUSD,M1: 750000 elements. Add: 1061; Get: 171
2015.03.23 13:25:44.320 TestDict EURUSD,M1: 700000 elements. Add: 1107; Get: 156
2015.03.23 13:25:42.761 TestDict EURUSD,M1: 650000 elements. Add: 1045; Get: 140
2015.03.23 13:25:41.304 TestDict EURUSD,M1: 600000 elements. Add: 1014; Get: 156
2015.03.23 13:25:39.915 TestDict EURUSD,M1: 550000 elements. Add: 920; Get: 125
2015.03.23 13:25:38.665 TestDict EURUSD,M1: 500000 elements. Add: 702; Get: 109
2015.03.23 13:25:37.693 TestDict EURUSD,M1: 450000 elements. Add: 593; Get: 93
2015.03.23 13:25:36.836 TestDict EURUSD,M1: 400000 elements. Add: 577; Get: 78
2015.03.23 13:25:36.025 TestDict EURUSD,M1: 350000 elements. Add: 561; Get: 78
2015.03.23 13:25:35.247 TestDict EURUSD,M1: 300000 elements. Add: 515; Get: 78
2015.03.23 13:25:34.557 TestDict EURUSD,M1: 250000 elements. Add: 343; Get: 63
2015.03.23 13:25:34.063 TestDict EURUSD,M1: 200000 elements. Add: 312; Get: 47
2015.03.23 13:25:33.632 TestDict EURUSD,M1: 150000 elements. Add: 281; Get: 31
2015.03.23 13:25:33.264 TestDict EURUSD,M1: 100000 elements. Add: 171; Get: 16
2015.03.23 13:25:33.038 TestDict EURUSD,M1: 50000 elements. Add: 47; Get: 16
 
VDev:

Tolle Arbeit, Hut ab vor dem Autor! Das ist etwas, das MQ schon vor langer Zeit in MQL5/Include/Arrays hätte aufnehmen sollen, ich hoffe, es wird in den nächsten Versionen in die Bibliothek aufgenommen. Übrigens funktioniert auch in MQL4 alles einwandfrei, hier sind die Messungen des ersten Tests. Ich verstehe, dass es unmöglich ist, einfache Datentypen anstelle von *CObject aufgrund des Fehlens von vollwertigen Zeigern einzubeziehen? Oder gibt es eine Möglichkeit, es zum Laufen zu bringen?

Es wird funktionieren. Mit Hilfe des Boxing/Unboxing-Mechanismus und Vorlagen. Die Idee ist, dass jeder Basistyp in einen KeyValuePairBase-Container gepackt wird. Das Auspacken und die Rückgabe des entsprechenden Typs erfolgt über interne Funktionen vom Typ GetObjectByKey:

template<typename Type, typename T>
Type GetObjectByKey(T key);

Es ist wichtig zu betonen, dass die Arbeit mit Basistypen keinen Leistungsvorteil bringt, aber sehr viel bequemer ist.

 

Jetzt habe ich versucht, eine CDictionaryBase zu erstellen, die einen der grundlegenden MQL-Typen anstelle von CObject auf der Grundlage von Vorlagen speichert. Leider hat es nicht geklappt, die Funktionen erlauben es nicht, einen Template-Typ zurückzugeben. Das ist schade:

//+------------------------------------------------------------------+
//|TestDictBase.mq5 |
//|Copyright 2015, Vasiliy Sokolov. |
//|http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#property version   "1.00"
#include <Dictionary.mqh>
#include <DictionaryBase.mqh>
//+------------------------------------------------------------------+
//| Skript-Programmstartfunktion|
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   CDictionaryBase base;
   base.AddValue("Pi", 3.14159);
   double pi = (double)base.GetValueByKey("Pi");
   printf(DoubleToString(pi, 5));
   //base.AddObject(
  }
//+------------------------------------------------------------------+
could not deduce template argument #1    TestDictBase.mq5        19      29
could not deduce template argument #0    DictionaryBase.mqh      404     25
possible loss of data due to type conversion    DictionaryBase.mqh      133     10
possible loss of data due to type conversion    DictionaryBase.mqh      135     10
possible loss of data due to type conversion    DictionaryBase.mqh      137     10
...

//+------------------------------------------------------------------+
//| Gibt das Objekt nach Schlüssel zurück.|
//+------------------------------------------------------------------+
template<typename T, typename C>
C CDictionaryBase::GetValueByKey(T key)
  {
   if(!ContainsKey(key))
      return NULL;
   return m_current_kvp.GetValue();
  }

Sehr schade.

Also müssen wir für jeden Basistyp einen Basiscontainer erstellen, oder einfach Container von Basistypen erstellen: CDouble, CLong, CInt, etc.

 
C-4:

Jetzt habe ich versucht, eine CDictionaryBase zu erstellen, die einen der grundlegenden MQL-Typen anstelle von CObject auf der Grundlage von Vorlagen speichert. Leider ist es mir nicht gelungen, die Funktionen erlauben es nicht, einen Template-Typ zurückzugeben.

Sie tun es. Aber der Typ des zurückgegebenen Wertes kann nicht automatisch abgeleitet werden, das schreibt eigentlich der Compiler.

Sie können eine kleine Krücke in Form eines Pseudoparameters verwenden.

template<typename T, typename C>
C CDictionaryBase::GetValueByKey(T key, C)
{
   if(!ContainsKey(key))
      return NULL;
   return m_current_kvp.GetValue();
}
 
TheXpert:

Das tun sie. Aber der Typ des zurückgegebenen Wertes kann nicht automatisch abgeleitet werden, was der Compiler eigentlich schreibt.

Sie können eine kleine Krücke in Form eines Pseudoparameters verwenden.

Wo ist die eigentliche Krücke?
 
C-4:
Wo ist die eigentliche Krücke?
Ein zweiter Parameter wurde hinzugefügt
 
TheXpert:
Ein zweiter Parameter wurde hinzugefügt
Ich sehe ihn jetzt. Ich werde ihn morgen überprüfen.
 
Haben Sie versucht, die Leistung zu vergleichen. Bei welcher Datengröße beginnt der Vorteil gegenüber der binären Suche in einem sortierten String-Array?
 
Integer:
Haben Sie versucht, die Leistung zu vergleichen. Bei welcher Datengröße beginnt der Vorteil gegenüber der binären Suche in einem sortierten String-Array?

Ich habe keine genauen Tests gemacht, aber nach meinen Beobachtungen beginnt der Geschwindigkeitsvorteil ab zehntausenden von Elementen. D.h. bei alltäglichen Aufgaben mit 100-10 000 Elementen kann man keinen Leistungsgewinn erzielen.

Ein weiterer Punkt ist hier wichtig, nämlich die Bequemlichkeit der Arbeit mit dem Container. Man braucht keine zusätzlichen Methoden zu schreiben, um nach Elementen zu suchen. Viele alltägliche Aufgaben mit Wörterbüchern werden um ein Vielfaches einfacher zu implementieren. Man braucht kein Element zu erstellen, um nach einem Index zu suchen, dann das benötigte Element über den entsprechenden Index abzurufen, usw. usw.

s.s. Hier dachte ich allerdings, dass die Leistung als Gesamtzeit für das Einfügen von Elementen und deren Suche gemessen werden sollte. Und wenn die Suche nach sortierten Elementen in CArrayObj eine recht schnelle Operation ist, dann ist das Einfügen ein echtes Problem. Da eine schnelle Suche Ordnungsmäßigkeit voraussetzt, können wir mögliche Einfügungen nicht ausschließen, was die Leistung erheblich verlangsamt.

 

Sehr interessant und es ist klar, dass das Wörterbuch sehr hilfreich und einfach zu benutzen ist.


Vielen Dank für Ihren Beitrag.