Обсуждение статьи "Рецепты MQL5 - Реализуем ассоциативный массив или словарь для быстрого доступа к данным" - страница 3

 
vek_y4icb:

Доброго времени суток! А не подскажете как циклом пройти по всему словарю, удаляя при этом пары по определенному условию, что-то не могу догнать. Вот пример такой задачи.

Хороший вопрос. Сейчас проверил удаление Вашим способом - оно не работает корректно. Буду разбираться.

 
Vasiliy Sokolov:

Хороший вопрос. Сейчас проверил удаление Вашим способом - оно не работает корректно. Буду разбираться.

оно и не должно работать корректно в общем случае.

правильный способ множественного удаления из ассоциативного массива - собрать массив удаляемых ключей, затем удалить по ключу.

 
Andrei Trukhanovich:

оно и не должно работать корректно в общем случае.

правильный способ множественного удаления из ассоциативного массива - собрать массив удаляемых ключей, затем удалить по ключу.

Это понятно, но опять же лишние телодвижения. 

 
Vasiliy Sokolov:

Хороший вопрос. Сейчас проверил удаление Вашим способом - оно не работает корректно. Буду разбираться.

Спасибо за отклик!

 
Andrei Trukhanovich:

оно и не должно работать корректно в общем случае.

правильный способ множественного удаления из ассоциативного массива - собрать массив удаляемых ключей, затем удалить по ключу.

Да вот в том-то и дело, что даже такой способ вдруг вызвал странный баг. Там явно ошибка. Буду разбираться в чем дело.

Пока могу посоветовать создать новый словарь, и в него добавлять значения которые не нужно удалять. Затем старый очистить. Это 100% сработает.

 

Значит так:

1. Обновляем версию Dictionary на ту что прикреплена к этому посту.

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(). Единственная причина по которой он доступен как public это то, что именно в этом кейсе вызов метода позволяет сэкономить время на повторном позиционировании указателя. Т.е. типичный и единственный случай его использования это 1. Проверили есть ли ключ, 2. если есть - удалили его быстро этим методом.

Файлы:
 
vek_y4icb:

Это понятно, но опять же лишние телодвижения. 

Технически возможно однопроходное удаление как Вы ожидаете. Но сложновато будет. Поэтому пока нет, только в два прохода. С точки зрения словаря как распределенной структуры данных, двухпроходное удаление является более канонически правильным решением. Это только на уровне пользователя кажется что удаление идет последовательно, на самом деле все иначе устроено. В плане перфоманса однопроходное удаление не принесет каких-либо бенефитов. В плане удобства - да, это может быть более удобным. 

 
Vasiliy Sokolov:

Технически возможно однопроходное удаление как Вы ожидаете. Но сложновато будет. Поэтому пока нет, только в два прохода. С точки зрения словаря как распределенной структуры данных, двухпроходное удаление является более канонически правильным решением. Это только на уровне пользователя кажется что удаление идет последовательно, на самом деле все иначе устроено. В плане перфоманса однопроходное удаление не принесет каких-либо бенефитов. В плане удобства - да, это может быть более удобным. 

Спасибо.

Причина обращения: