記事"MQL5 クックブック: 連想配列またはクイック データアクセスのための辞書の実装"についてのディスカッション - ページ 4

 
Vasiliy Sokolov:

これにはいくつかの理由が考えられる。最も考えられるのは、型の非互換性か、ポインタの不適切な扱いだ。また、テンプレート・メソッドの特殊性も排除できません(そこにも独自のニュアンスがあります)。

一般的には、既製のトレーディング・エンジンを使う方がよいでしょう。https://www.mql5.com/ja/articles/2166、多くの時間と神経を節約できます。

こんにちは!辞書全体をループし、特定の条件によってペアを削除する方法を教えてください。以下はそのようなタスクの例です。

#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() または d.DeleteObjectByKey(node.value);
         
      // 辞書を反復処理するには? 
     }
     
   return(INIT_SUCCEEDED);
  }
 
vek_y4icb:

こんにちは!辞書全体をループして、ある条件でペアを削除する方法を教えてください。以下はそのようなタスクの例です。

いい質問ですね。今、私はあなたの方法を使用して削除をチェックしました - それは正しく動作しません。調べてみます。

 
Vasiliy Sokolov:

いい質問ですね。あなたの方法で削除を確認しましたが、正しく動作しませんでした。調べてみます。

一般的なケースでは正しく動作しないはずです。

連想配列から複数の削除を行う正しい方法は、削除するキーの配列を収集し、キーごとに削除することです。

 
Andrei Trukhanovich:

一般的に正しく機能する必要はない。

連想配列から複数回の削除を行う正しい方法は、削除するキーの配列を収集し、キーごとに削除することです。

これは理解できるが、やはり不必要な作業だ。

 
Vasiliy Sokolov:

いい質問ですね。あなたの方法で削除を確認しましたが、正しく動作しませんでした。調べてみます。

ご回答ありがとうございました!

 
Andrei Trukhanovich:

一般的に正しく機能する必要はない。

連想配列から複数回削除を実行する正しい方法は、削除するキーの配列を収集し、キーごとに削除することです。

そこが問題で、この方法でも突然おかしなバグが発生する。明らかにエラーだ。調べてみます。

とりあえず、新しい辞書を作り、そこに削除する必要のない値を追加してください。それから古い辞書を消去してください。これで100%うまくいくでしょう。

 

さあ、始めよう:

1. 辞書バージョンをこの投稿に添付されているものに更新する。

2.要素を削除するテストスクリプトを実行する。

削除は2回に分けて行う:

int OnStart()
  {
   d.FreeMode(true);
   for(int i = 0; i < 10; ++i)
   {
      CInt *int_value = new CInt(i);
      d.AddObject(i, int_value);
   }
   //-- 削除するキーのリストを作成する
   CArrayInt delKeys;
   for(CInt *node = d.GetFirstNode(); node != NULL; node = d.GetNextNode())
   {
      if(node.value % 2 == 0)
         delKeys.Add(node.value);
   }
   //-- 削除が割り当てられたオブジェクトを、それぞれ個別に削除する。
   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);
  }

DeleteCurrentObject() メソッドについて:

このメソッドは、ContainsKey() 関数と組み合わせてのみ使用する必要があります。このメソッドがパブリックとして利用可能な唯一の理由は、この場合、メソッド呼び出しによってポインタを再配置する時間を節約できるからです。つまり、典型的かつ唯一の使用例は、1.キーがあるかどうかをチェックする。

ファイル:
 
vek_y4icb:

それは理解できるが、やはり不必要なボディワークだ。

技術的には、あなたが期待するようにワンパスで取り外すことは可能です。しかし、それは複雑でしょう。そのため、まだ2パスしかしていない。分散データ構造としての ディクショナリーの観点からは、2パス削除の方がより正統的なソリューションである。削除が逐次的であるように見えるのはユーザー・レベルだけで、実際にはすべてが異なる。パフォーマンスという点では、シングルパス削除は何のメリットももたらさない。利便性という点では、そうかもしれない。

 
Vasiliy Sokolov:

技術的には、あなたが期待するようなワンパス除去は可能です。しかし、それは複雑です。そのため、まだ2パスしか行っていない。分散データ構造としての 辞書の観点からは、2パス削除の方がより正統的である。削除が逐次的であるように見えるのはユーザー・レベルだけで、実際にはすべてが異なる。パフォーマンスという点では、シングルパス削除は何のメリットももたらさない。利便性という点では、そうかもしれない。

ありがとう。

削除済み  
Marcel Fitzner:

要素を削除して最後の要素に行こうとしたときにバグを見つけたようだ:

CDictionary.mqhのエラーになります:

'Dictionary.mqh'の無効なポインタ・ アクセス (463,9)

どなたか確認できますか?修正方法があれば教えてください。



500行目と501行目のポインタチェックの実装のバグでした。

内蔵のCheckPointer()を使って修正しました。

ファイル:
CDictionary.mqh  21 kb