Discussione sull’articolo "MQL5 Cookbook: Implementazione di un array associativo o di un dizionario per l'accesso rapido ai dati" - pagina 4

 
Vasiliy Sokolov:

Le ragioni possono essere diverse. Molto probabilmente si tratta di incompatibilità di tipo o di una gestione non corretta dei puntatori. Inoltre, non possiamo escludere le peculiarità del lavoro con i metodi template (anche lì ci sono le loro sfumature).

In generale, è meglio utilizzare un motore di trading già pronto, che vi farà risparmiare molto tempo e nervi: https://www.mql5.com/it/articles/2166.

Buon pomeriggio! Potete dirmi come fare un ciclo attraverso l'intero dizionario, rimuovendo le coppie in base a una certa condizione, cosa che non riesco a fare. Ecco un esempio di tale operazione.

#include <Dictionary.mqh>

class CInt : public CObject
  {
public:
   int               value;
                     CInt(int _value = 0) : value(_value) {}
  };
  
CDictionary d;
//+------------------------------------------------------------------+
//||
//+------------------------------------------------------------------+
int OnInit()
  {
   d.FreeMode(true);
   for(int i = 0; i < 10; ++i)
     {
      CInt *int_value = new CInt(i);
      d.AddObject(i, int_value);
     }
   for(CInt *node = d.GetFirstNode(); node != NULL;)
     {
      if(node.value % 2 == 0)
         // d.DeleteCurrentNode() o d.DeleteObjectByKey(node.value);
         
      // Come iterare il dizionario???? 
     }
     
   return(INIT_SUCCEEDED);
  }
 
vek_y4icb:

Buon pomeriggio! Potete dirmi come fare un ciclo attraverso l'intero dizionario, rimuovendo le coppie in base a una certa condizione, qualcosa che non riesco a recuperare. Ecco un esempio di tale compito.

Buona domanda. Ora ho controllato l'eliminazione con il tuo metodo - non funziona correttamente. Ci penserò.

 
Vasiliy Sokolov:

Buona domanda. Ho verificato l'eliminazione con il tuo metodo e non funziona correttamente. Ci penserò.

Non dovrebbe funzionare correttamente nel caso generale.

Il modo corretto per eseguire eliminazioni multiple da un array associativo è quello di raccogliere un array di chiavi da eliminare, quindi eliminare per chiave.

 
Andrei Trukhanovich:

non deve funzionare correttamente in generale.

Il modo corretto per eseguire cancellazioni multiple da un array associativo è quello di raccogliere un array di chiavi da cancellare, quindi cancellare per chiave.

Questo è comprensibile, ma ancora una volta è un lavoro inutile.

 
Vasiliy Sokolov:

Buona domanda. Ho verificato l'eliminazione con il tuo metodo e non funziona correttamente. Ci penserò.

Grazie per la risposta!

 
Andrei Trukhanovich:

non deve funzionare correttamente in generale.

il modo corretto per eseguire cancellazioni multiple da un array associativo è raccogliere un array di chiavi da cancellare, quindi cancellare per chiave.

Questo è il punto, anche questo metodo causa improvvisamente uno strano bug. È ovviamente un errore. Lo esaminerò.

Per ora, posso consigliarvi di creare un nuovo dizionario e di aggiungervi i valori che non devono essere eliminati. Quindi cancellare quello vecchio. Questo funzionerà al 100%.

 

Ecco come procedere:

1. aggiornare la versione del Dizionario a quella allegata a questo post.

2. Eseguire uno script di prova per eliminare anche gli elementi.

L'eliminazione dovrebbe avvenire in due passaggi:

int OnStart()
  {
   d.FreeMode(true);
   for(int i = 0; i < 10; ++i)
   {
      CInt *int_value = new CInt(i);
      d.AddObject(i, int_value);
   }
   //-- Creare un elenco di chiavi da cancellare
   CArrayInt delKeys;
   for(CInt *node = d.GetFirstNode(); node != NULL; node = d.GetNextNode())
   {
      if(node.value % 2 == 0)
         delKeys.Add(node.value);
   }
   //-- Elimina gli oggetti assegnati per la cancellazione, ognuno separatamente.
   for(int i = 0; i < delKeys.Total(); i++)
      d.DeleteObjectByKey(delKeys.At(i));
   for(CInt *node = d.GetFirstNode(); node != NULL; node = d.GetNextNode())
   {
      printf(node.value);
   }
     
   return(INIT_SUCCEEDED);
  }

Per quanto riguarda il metodo DeleteCurrentObject():

Questo metodo deve essere usato solo insieme alla funzione ContainsKey(). L'unico motivo per cui è disponibile come pubblico è che in questo caso la chiamata al metodo fa risparmiare tempo al riposizionamento del puntatore. Cioè, il tipico e unico caso di utilizzo è 1. Controllare se c'è una chiave, 2. Controllare se c'è una chiave. Controllare se c'è una chiave, 2. Se c'è, cancellarla rapidamente con questo metodo.

File:
 
vek_y4icb:

È comprensibile, ma anche in questo caso la carrozzeria non è necessaria.

È tecnicamente possibile eseguire una rimozione in un unico passaggio, come si prevede. Ma sarebbe complicato. Ecco perché non ancora, solo in due passaggi. Dal punto di vista del dizionario come struttura dati distribuita, la cancellazione in due passaggi è una soluzione più canonicamente corretta. Solo a livello di utente sembra che la cancellazione sia sequenziale, in realtà è tutto diverso. In termini di prestazioni, la cancellazione in un solo passaggio non porterà alcun beneficio. In termini di comodità, sì, potrebbe essere più conveniente.

 
Vasiliy Sokolov:

È tecnicamente possibile eseguire una rimozione in un unico passaggio, come previsto. Ma sarebbe complicato. Per questo motivo non è ancora possibile, ma solo in due passaggi. Dal punto di vista del dizionario come struttura dati distribuita, l'eliminazione in due passaggi è più canonicamente corretta. Solo a livello di utente sembra che la cancellazione sia sequenziale, in realtà è tutto diverso. In termini di prestazioni, la cancellazione in un solo passaggio non porterà alcun beneficio. In termini di comodità, sì, potrebbe essere più conveniente.

Grazie.

[Eliminato]  
Marcel Fitzner:

Credo di aver trovato un errore quando si elimina un elemento e si cerca di raggiungere l'ultimo elemento:

L'errore nel CDictionary.mqh sarà:

accessoal puntatore non valido in 'Dictionary.mqh' (463,9)

Qualcuno può confermarlo? Qualche idea su come risolvere il problema?



Si trattava di un bug nelle righe 500 e 501 dell'implementazione del controllo dei puntatori.

È stato risolto utilizzando CheckPointer() integrato.

File:
CDictionary.mqh  21 kb