Как отфильтровать элементы из std :: map?

У меня примерно следующий код. Можно ли сделать это лучше или эффективнее? Возможно, используя std::remove_if? Можете ли вы удалить предметы с карты, путешествуя по ней? Можно ли избежать использования временной карты?

typedef std::map<Action, What> Actions;
static Actions _actions;

bool expired(const Actions::value_type &action)
{
  return <something>;
}

void bar(const Actions::value_type &action)
{
  // do some stuff
}

void foo()
{
  // loop the actions finding expired items
  Actions actions;
  BOOST_FOREACH(Actions::value_type &action, _actions)
  {
    if (expired(action))
      bar(action);
    else
      actions[action.first]=action.second;
    }
  }
  actions.swap(_actions);
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
28
0
21 316
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если идея состоит в том, чтобы удалить просроченные элементы, почему бы не использовать карта :: стереть? Таким образом, вам нужно только удалить элементы, которые вам больше не нужны, а не перестраивать всю копию со всеми элементами, которые вы хотите сохранить.

То, как вы это сделаете, - это сохранить итераторы, указывающие на элементы, которые вы хотите удалить, а затем стереть их все после завершения итерации.

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

В зависимости от того, как реализован expired (), могут быть другие лучшие способы. Например, если вы отслеживаете метку времени в качестве ключа к карте (как подразумевает expired ()?), Вы можете сделать upper_bound для текущей метки времени, и все элементы в диапазоне [begin (), upper_bound ()) должны для обработки и стирания.

Ответ принят как подходящий

Вы можете использовать erase (), но я не знаю, как BOOST_FOREACH обработает недействительный итератор. документация для map :: erase указывает, что только стертый итератор будет признан недействительным, остальные должны быть в порядке. Вот как бы я реструктурировал внутренний цикл:

Actions::iterator it = _actions.begin();
while (it != _actions.end())
{
  if (expired(*it))
  {
    bar(*it);
    Actions::iterator toerase = it;
    ++it;
    _actions.erase(toerase);
  }
  else
    ++it;
}

Пожалуйста, не используйте решение, представленное в этом (устаревшем) ответе. Его поведение зависит от контейнера. Начиная с C++ 11 существует гораздо лучшее решение: erase возвращает новый итератор элементу, следующему за удаленным элементом. for(auto it = container.begin(); it != container.end(); ) if (to_delete(it)) it = container.erase(it); else ++it;

Andreas H. 03.07.2020 08:12

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

Actions::iterator it = _actions.begin();
while (it != _actions.end())
{
  if (expired(*it))
  {
    bar(*it);
    it = _actions::erase(it);
  }
  else
    ++it;
}

Хранение actions.end (), вероятно, не является хорошим планом в этом случае, поскольку я считаю, что стабильность итератора не гарантируется.

Согласно документации, которую я привел в своем ответе, erase возвращает void, и ваш образец кода не компилируется.

Mark Ransom 08.10.2008 02:25

Думаю, это расширение на VC++.

1800 INFORMATION 08.10.2008 03:08

Это не верно для любого Контейнера, только для тех, которые являются моделями Последовательности. Для контейнеров, которые являются моделью ассоциативного контейнера, тип возврата erase имеет значение void.

camh 08.10.2008 03:29

Как насчет this vector :: erase doc? Он четко говорит, что у него есть итератор возврата erase (). Ничего не говорится о том, что это расширение MS.

Marcin Gil 08.10.2008 12:16

@Marcin, стирание std :: vector возвращает итератор. Но это обсуждение std :: map. У которого есть стирание, которое возвращает пустоту.

Evan Teran 08.10.2008 21:37

Похоже, map :: erase () тоже должен вернуть итератор: open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2728.html#130

Constantin 26.05.2010 11:56

VC2013 std :: map :: erase возвращает итератор ..

paulm 20.10.2014 04:12

С появлением C++ 11 этот ответ теперь верен. +1

Martin York 09.12.2014 02:55

Вариант алгоритма Марка Рэнсома, но без необходимости во временном.

for(Actions::iterator it = _actions.begin();it != _actions.end();)
{
    if (expired(*it))
    {
        bar(*it);
        _actions.erase(it++);  // Note the post increment here.
                               // This increments 'it' and returns a copy of
                               // the original 'it' to be used by erase()
    }
    else
    {
        ++it;  // Use Pre-Increment here as it is more effecient
               // Because no copy of it is required.
    }
}

Отлично сделано. Жаль, что мне потребовалось два с половиной года, чтобы увидеть это усовершенствование.

Mark Ransom 01.03.2011 21:31

@Mark Ransom: Ничего страшного. Мы все еще можем назвать его Mark Ransom technique :-)

Martin York 01.03.2011 22:02

Спасибо @Mark Ransom и @Martin. Так много информации в этом коде. Мне всегда было интересно, почему Страуструп предпочитает ++ i.

matiu 25.06.2011 07:23

Другие вопросы по теме