Discussion de l'article "Le MQL5 Cookbook : Implémentation d'un tableau associatif ou d'un dictionnaire pour un accès rapide aux données"
Article publié Recettes MQL5 - Implémenter un tableau associatif ou un dictionnaire pour un accès rapide aux données:
Auteur : Vasiliy Sokolov
Bon travail, bravo à l'auteur ! C'est quelque chose que MQ aurait dû inclure dans \MQL5\Include\Arrays depuis longtemps, j'espère qu'il sera inclus dans la bibliothèque dans les prochaines versions. Au fait, tout fonctionne bien dans MQL4 également, voici les mesures du premier test. Je comprends qu'il est impossible d'inclure des types de données simples à la place de *CObject en raison de l'absence de pointeurs à part entière ? Ou existe-t-il un moyen de contourner ce problème ?
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
Bon travail, bravo à l'auteur ! C'est quelque chose que MQ aurait dû inclure dans MQL5/Include/ Arrays il y a longtemps, j'espère que cela sera inclus dans la bibliothèque dans les prochaines versions. Au fait, tout fonctionne bien dans MQL4 également, voici les mesures du premier test. Je comprends qu'il est impossible d'inclure des types de données simples à la place de *CObject en raison de l'absence de pointeurs à part entière ? Ou existe-t-il un moyen de le faire fonctionner ?
Cela fonctionnera. Avec l'aide du mécanisme de boxing/unboxing et des templates. L'idée est que chaque type de base est emballé dans un conteneur KeyValuePairBase. Le déballage et le renvoi du type correspondant sont effectués par les fonctions internes du type GetObjectByKey :
template<typename Type, typename T>
Type GetObjectByKey(T key);Il est important de souligner que le fait de travailler avec des types de base n'apportera aucun avantage en termes de performances, mais sera beaucoup plus pratique.
J'ai essayé de créer un CDictionaryBase stockant l'un des types de base de MQL au lieu d'un CObject sur la base de modèles. Malheureusement, cela n'a pas fonctionné, les fonctions ne permettent pas de retourner un type template. C'est dommage :
//+------------------------------------------------------------------+ //|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> //+------------------------------------------------------------------+ //| Fonction de démarrage du programme de script| //+------------------------------------------------------------------+ 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 ...
//+------------------------------------------------------------------+ //| Retourne l'objet par clé.| //+------------------------------------------------------------------+ template<typename T, typename C> C CDictionaryBase::GetValueByKey(T key) { if(!ContainsKey(key)) return NULL; return m_current_kvp.GetValue(); }
Dommage.
Donc, pour chaque type de base, nous devrons créer un conteneur de base, ou simplement créer des conteneurs de types de base : CDouble, CLong, CInt, etc.
J'ai essayé de créer un CDictionaryBase stockant l'un des types de base de MQL au lieu de CObject sur la base de modèles. Malheureusement, je n'y suis pas parvenu, car les fonctions ne permettent pas de renvoyer un type de modèle.
Elles le font. Mais le type de la valeur retournée ne peut pas être déduit automatiquement, ce qui est en fait écrit par le compilateur.
Vous pouvez utiliser une petite béquille sous la forme d'un pseudo-paramètre.
template<typename T, typename C> C CDictionaryBase::GetValueByKey(T key, C) { if(!ContainsKey(key)) return NULL; return m_current_kvp.GetValue(); }
C'est le cas. Mais le type de la valeur retournée ne peut pas être déduit automatiquement, ce que le compilateur écrit en réalité.
Vous pouvez utiliser une petite béquille sous la forme d'un pseudo-paramètre.
Où se trouve la véritable béquille ?
Avez-vous essayé de comparer les performances. À partir de quelle taille de données l'avantage par rapport à la recherche binaire dans un tableau de chaînes triées commence-t-il à se manifester ?
Je n'ai pas effectué de tests précis, mais d'après mes observations, l'avantage en termes de vitesse commence à apparaître à partir de dizaines de milliers d'éléments. En d'autres termes, dans les tâches quotidiennes comportant 100 à 10 000 éléments, il n'est pas possible d'obtenir un gain de performance.
Une autre chose est importante ici, à savoir la commodité de travailler avec le conteneur. Il n'est pas nécessaire d'écrire des méthodes supplémentaires pour rechercher des éléments. De nombreuses tâches quotidiennes avec les dictionnaires deviennent beaucoup plus faciles à mettre en œuvre. Il n'est pas nécessaire de créer un élément pour rechercher un index, puis de récupérer l'élément nécessaire par l'index correspondant, etc.
s.s. Je pensais que les performances devaient être mesurées en fonction du temps total d'insertion et de recherche des éléments. Et si la recherche d'éléments triés dans CArrayObj est une opération assez rapide, alors l'insertion est un vrai problème. Puisque la recherche rapide nécessite de l'ordre, vous ne pouvez pas vous débarrasser des insertions possibles, et cela ralentira considérablement les performances.
Très intéressant et il est clair que le dictionnaire est un organisateur de données très utile et facile à utiliser.
Merci pour votre partage.
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation
Un nouvel article Le MQL5 Cookbook : Implémentation d'un tableau associatif ou d'un dictionnaire pour un accès rapide aux données a été publié :
Cet article décrit un algorithme spécial permettant d'accéder aux éléments par leurs clés uniques. Tout type de données de base peut être utilisé comme clé. Par exemple, elles peuvent être représentées sous la forme d'une chaîne ou d'une variable entière. Un tel conteneur de données est communément appelé dictionnaire ou tableau associatif. Il fournit un moyen plus facile et plus efficace de résoudre les problèmes.
Ce code fonctionnera, mais il est assez risqué car nous manipulons directement les index du tableau.
Si nous calculons mal la taille de notre tableau arrayObj ou l’adresse par un mauvais index, notre programme se retrouvera avec une erreur critique. Mais ce code convient à nos fins de démonstration.
Présentons ces éléments sous forme de schéma :
Fig. 1. Schéma de stockage des données dans le tableau de pointeurs
Les éléments, créés par l'opérateur 'nouveau', sont stockés dans une partie spéciale de la mémoire vive qui s'appelle un tas. Ces éléments ne sont pas ordonnés comme on peut le voir clairement sur le schéma ci-dessus.
Auteur : Vasiliy Sokolov