Discusión sobre el artículo "Recetas de MQL5 - implementamos el array asociativo o el diccionario para el acceso rápido a los datos" - página 4

 
Vasiliy Sokolov:

Esto puede deberse a varias razones. La más probable es la incompatibilidad de tipos o el manejo incorrecto de los punteros. Además, no podemos excluir peculiaridades de trabajar con métodos de plantilla (hay sus propios matices allí también).

En general, es mejor utilizar un motor de operaciones ya hecho, ahorrará mucho tiempo y nervios: https://www.mql5.com/es/articles/2166.

Buenas tardes¡ Me podeis decir como hacer un bucle por todo el diccionario, eliminando pares por una determinada condición, algo que no consigo pillar. Aquí tienes un ejemplo de dicha tarea.

#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);
         
      // Cómo iterar a través del diccionario???? 
     }
     
   return(INIT_SUCCEEDED);
  }
 
vek_y4icb:

Buenas tardes! Me podeis decir como hacer un bucle a través de todo el diccionario, eliminando los pares por una determinada condición, algo que no consigo pillar. He aquí un ejemplo de dicha tarea.

Buena pregunta. Ahora he comprobado el borrado utilizando su método - no funciona correctamente. Voy a mirar en él.

 
Vasiliy Sokolov:

Buena pregunta. Ahora he comprobado el borrado con tu método: no funciona correctamente. Lo investigaré.

No debería funcionar correctamente en el caso general.

La forma correcta de realizar borrados múltiples de un array asociativo es recoger un array de claves a borrar, y luego borrar por clave.

 
Andrei Trukhanovich:

no tiene por qué funcionar correctamente en general.

la forma correcta de realizar borrados múltiples desde un array asociativo es recoger un array de claves a borrar, y luego borrar por clave.

Esto es comprensible, pero de nuevo es trabajo innecesario.

 
Vasiliy Sokolov:

Buena pregunta. Ahora he comprobado el borrado con tu método: no funciona correctamente. Lo investigaré.

Gracias por la respuesta.

 
Andrei Trukhanovich:

no tiene por qué funcionar correctamente en general.

la forma correcta de realizar borrados múltiples desde un array asociativo es recoger un array de claves a borrar, y luego borrar por clave.

Esa es la cuestión, incluso este método de repente causa un extraño error. Obviamente es un error. Lo investigaré.

Por ahora, puedo aconsejarle que cree un nuevo diccionario, y añada a él los valores que no necesitan ser borrados. Luego borre el antiguo. Esto funcionará al 100%.

 

Aquí va:

1. actualizar la versión del Diccionario a la que se adjunta en este post.

2. Ejecute un script de prueba para borrar elementos pares.

El borrado debería hacerse en dos pasadas:

int OnStart()
  {
   d.FreeMode(true);
   for(int i = 0; i < 10; ++i)
   {
      CInt *int_value = new CInt(i);
      d.AddObject(i, int_value);
   }
   //-- Crear una lista de claves a borrar
   CArrayInt delKeys;
   for(CInt *node = d.GetFirstNode(); node != NULL; node = d.GetNextNode())
   {
      if(node.value % 2 == 0)
         delKeys.Add(node.value);
   }
   //-- Borrar los objetos asignados para borrado, cada uno por separado.
   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);
  }

Con respecto al método DeleteCurrentObject():

Este método sólo debe utilizarse junto con la función ContainsKey(). La única razón por la que está disponible como público es que en este caso la llamada al método ahorra tiempo en el reposicionamiento del puntero. Es decir, el típico y único caso de su uso es 1. Comprobar si hay una clave, 2. Si la hay - borrarla rápidamente con este método.

Archivos adjuntos:
 
vek_y4icb:

Es comprensible, pero de nuevo, una carrocería innecesaria.

Técnicamente es posible hacer un desmontaje de una pasada como esperas. Pero sería complicado. Por eso todavía no, sólo en dos pasadas. Desde el punto de vista del diccionario como estructura de datos distribuida, la eliminación en dos pasadas es una solución canónicamente más correcta. Sólo a nivel de usuario parece que el borrado es secuencial, en realidad todo es diferente. En términos de rendimiento, el borrado en una sola pasada no aportará ninguna ventaja. En términos de comodidad, sí, puede ser más conveniente.

 
Vasiliy Sokolov:

Técnicamente es posible hacer una eliminación de un solo paso como usted espera. Pero sería complicado. Por eso todavía no, sólo en dos pasadas. Desde el punto de vista del diccionario como estructura de datos distribuida, el borrado en dos pasadas es más canónicamente correcto. Sólo a nivel de usuario parece que el borrado es secuencial, en realidad todo es diferente. En términos de rendimiento, el borrado en una sola pasada no aportará ninguna ventaja. En términos de comodidad, sí, puede ser más conveniente.

Gracias.

[Eliminado]  
Marcel Fitzner:

Creo que he encontrado un error al borrar un elemento e intentar llegar al último elemento:

El error en el CDictionary.mqh será:

invalid pointer access in 'Dictionary.mqh' (463,9)

¿Alguien puede confirmarlo? ¿Alguna idea para solucionarlo?



Era un error en la línea 500 && 501 en la implementación de la comprobación de los punteros.

Arreglado usando CheckPointer() incorporado.

Archivos adjuntos:
CDictionary.mqh  21 kb