Discussão do artigo "Guia Prático MQL5: Implementando um Array Associativo ou um Dicionário para Acesso Rápido ao Dados" - página 4

 
Vasiliy Sokolov:

Pode haver vários motivos para isso. O mais provável é a incompatibilidade de tipos ou o manuseio incorreto de ponteiros. Além disso, não podemos excluir as peculiaridades do trabalho com métodos de modelo (também há suas próprias nuances).

Em geral, é melhor usar um mecanismo de negociação pronto, pois você economizará muito tempo e nervosismo: https://www.mql5.com/pt/articles/2166.

Boa tarde! Você poderia me dizer como fazer um loop em todo o dicionário, removendo pares por uma determinada condição, algo que não consigo entender? Aqui está um exemplo de uma tarefa desse tipo.

#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() ou d.DeleteObjectByKey(node.value);
         
      // Como iterar pelo dicionário???? 
     }
     
   return(INIT_SUCCEEDED);
  }
 
vek_y4icb:

Boa tarde, você poderia me dizer como fazer um loop em todo o dicionário, removendo pares por uma determinada condição, algo que não consigo entender. Aqui está um exemplo de uma tarefa desse tipo.

Boa pergunta. Agora verifiquei a exclusão usando seu método - ele não funciona corretamente. Vou dar uma olhada nisso.

 
Vasiliy Sokolov:

Boa pergunta. Verifiquei agora a exclusão usando seu método - ela não funciona corretamente. Vou dar uma olhada nisso.

Ele não deve funcionar corretamente no caso geral.

A maneira correta de executar várias exclusões de uma matriz associativa é coletar uma matriz de chaves a serem excluídas e, em seguida, excluir por chave.

 
Andrei Trukhanovich:

não precisa funcionar corretamente em geral.

A maneira correta de realizar várias exclusões de uma matriz associativa é coletar uma matriz de chaves a serem excluídas e, em seguida, excluir por chave.

Isso é compreensível, mas, novamente, é um trabalho desnecessário.

 
Vasiliy Sokolov:

Boa pergunta. Verifiquei agora a exclusão usando seu método - ela não funciona corretamente. Vou dar uma olhada nisso.

Obrigado pela resposta!

 
Andrei Trukhanovich:

não precisa funcionar corretamente em geral.

A maneira correta de realizar várias exclusões de uma matriz associativa é coletar uma matriz de chaves a serem excluídas e, em seguida, excluir por chave.

O problema é que até mesmo esse método causa um erro estranho. Obviamente, é um erro. Vou dar uma olhada nisso.

Por enquanto, posso aconselhá-lo a criar um novo dicionário e adicionar a ele os valores que não precisam ser excluídos. Em seguida, limpe o antigo. Isso funcionará 100%.

 

Aqui vai:

1. Atualize a versão do Dictionary para a que está anexada a esta postagem.

2. Execute um script de teste para excluir elementos pares.

A exclusão deve ser feita em duas passagens:

int OnStart()
  {
   d.FreeMode(true);
   for(int i = 0; i < 10; ++i)
   {
      CInt *int_value = new CInt(i);
      d.AddObject(i, int_value);
   }
   //-- Criar uma lista de chaves a serem excluídas
   CArrayInt delKeys;
   for(CInt *node = d.GetFirstNode(); node != NULL; node = d.GetNextNode())
   {
      if(node.value % 2 == 0)
         delKeys.Add(node.value);
   }
   //-- Excluir objetos atribuídos para exclusão, cada um separadamente.
   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);
  }

Com relação ao método DeleteCurrentObject():

Esse método só deve ser usado em conjunto com a função ContainsKey(). A única razão pela qual ele está disponível como público é que, nesse caso, a chamada do método economiza tempo no reposicionamento do ponteiro. Ou seja, o caso típico e único de seu uso é 1. Verificar se há uma chave, 2. Se houver, excluí-la rapidamente com esse método.

Arquivos anexados:
 
vek_y4icb:

Isso é compreensível, mas, novamente, a carroceria é desnecessária.

Tecnicamente, é possível fazer uma remoção em uma única passagem, como você espera. Mas isso seria complicado. Por isso, ainda não é possível, apenas em duas passagens. Do ponto de vista do dicionário como uma estrutura de dados distribuída, a exclusão de duas passagens é uma solução canonicamente mais correta. Apenas no nível do usuário parece que a exclusão é sequencial, mas na realidade tudo é diferente. Em termos de desempenho, a exclusão de passagem única não trará nenhum benefício. Em termos de conveniência, sim, pode ser mais conveniente.

 
Vasiliy Sokolov:

Tecnicamente, é possível fazer uma remoção em uma única passagem, como você espera. Mas isso seria complicado. Por isso, ainda não é possível, apenas em duas passagens. Do ponto de vista do dicionário como uma estrutura de dados distribuída, a exclusão de duas passagens é mais canonicamente correta. Somente no nível do usuário parece que a exclusão é sequencial; na realidade, tudo é diferente. Em termos de desempenho, a exclusão de passagem única não trará nenhum benefício. Em termos de conveniência, sim, pode ser mais conveniente.

Obrigado.

[Excluído]  
Marcel Fitzner:

Acho que encontrei um erro ao excluir um elemento e tentar chegar ao último elemento:

O erro no CDictionary.mqh será:

acessoinválido aoponteiro em 'Dictionary.mqh' (463,9)

Alguém pode confirmar isso? Alguma ideia de como consertar?



Foi um erro na linha 500 && 501 na implementação da verificação dos ponteiros.

Corrigido usando o CheckPointer() embutido.

Arquivos anexados:
CDictionary.mqh  21 kb