map и удаление элементов.
От: Павел Кузнецов  
Дата: 27.10.04 22:20
Оценка: 30 (5) +2 -2
#Имя: FAQ.stl.map.erase
Wind:

> std::map <int, СЛОЖНАЯ_СТРУКТУРА> <...> задача удаления не нужных записей <...>

> 1) Перебираю каждый элемент списка на соответствие некоторым условиям
> 2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее
> Но вот незадача, после удаления элемента итераторы становятся не действительными

Только непосредственно удаленный.

> Что псоветуете?


for (MyMap::iterator i = m.begin(), e = m.end(); i != e; /* здесь пусто */ )
{
   if ( . . . )
     m.erase(i++);
   else
     ++i;
}
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Map и удаление элементов.
От: serega  
Дата: 28.10.04 07:08
Оценка: 6 (1) +1 -1
Привет
в доке все написано

Iterator map::erase (iterator Where)

Return value:
a bidirectional iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the map if no such element exists
Следовательно делаем так

for (it = map.begin();i != map.end();it++)
{
  if (условие)
  {
     it = map.erase(it); // it будет переброшен на первый верхний неизмененный елемент 
  }
}


Успехов

Здравствуйте, Wind,

Вы писали:

W>у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически возникает задача удаления не нужных записей, причем таких записей может быть несколько и расположены они могут быть в произвольных местах. Алгоритм, который мне пришел в голову:

W>1) Перебираю каждый элемент списка на соответствие некоторым условиям
W>2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее

W>Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.


W>Вот такая ерунда.

W>Что псоветуете?
Re[5]: Map и удаление элементов.
От: Анатолий Широков СССР  
Дата: 28.10.04 12:11
Оценка: :))
B>Щас придет Alexeib и вкатит тебе минус

Будет весело, если Alexeib прийдет и вкатит дяде Кодту плюc
Re[3]: Map и удаление элементов.
От: Павел Кузнецов  
Дата: 28.10.04 01:03
Оценка: +1
Sasparella:

> ПК> Только непосредственно удаленный.


> Угу, согласен — но имхо на это полагаться не стоит — ибо потом контейнер может смениться (ну, например на тот же вектор) — и искать багу придется очень долго....


Пытаться писать "контейнеро-независимый" код — дохлый номер. За исключением редких случаев, и у меня ощущение, что данный к ним не относится.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Map и удаление элементов.
От: itman itman.livejournal.com
Дата: 28.10.04 07:13
Оценка: -1
Здравствуйте, serega, Вы писали:

При этом будет регулярно пропускаться один элемент после удаляемого


S>Привет

S>в доке все написано

S>Iterator map::erase (iterator Where)


S>Return value:

S>a bidirectional iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the map if no such element exists
S>Следовательно делаем так

S>
S>for (it = map.begin();i != map.end();it++)
S>{
S>  if (условие)
S>  {
S>     it = map.erase(it); // it будет переброшен на первый верхний неизмененный елемент 
S>  }
S>}
S>


S>Успехов


Удалено излишнее цитирование
Re[2]: Map и удаление элементов.
От: Bell Россия  
Дата: 28.10.04 07:13
Оценка: -1
Здравствуйте, serega, Вы писали:


S>Привет

S>в доке все написано
S>Iterator map::erase (iterator Where)

Это "фича" реализации STL для VC6/7.По стандарту map::erase (iterator) возвращает void.
Любите книгу — источник знаний (с) М.Горький
Re[4]: Map и удаление элементов.
От: Bell Россия  
Дата: 28.10.04 11:50
Оценка: :)
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, itman, Вы писали:


S>>>в доке все написано


К>Эта дока называется MSDN и писана по Dinkumware STL, которая вот именно в этом месте отходит от Стандарта.

К>По Стандарту, void map::erase(map::iterator).

Щас придет Alexeib и вкатит тебе минус
Любите книгу — источник знаний (с) М.Горький
Re[6]: map и удаление элементов.
От: ssm Россия  
Дата: 29.10.04 07:57
Оценка: +1
Здравствуйте, Кодт, Вы писали:


К>А это не спасёт: добыча итератора на следующий за удалённым элемент в дереве — такая же дорогостоящая, как и простой инкремент. Ну может быть, чуть-чуть дешевле, если после перебалансировки расстояние между элементами в дереве сократилось.

К>Ну а если говорить точно, то время инкремента — O(log N).

имеется в виду, что при конструкции, не требующей нового итератора, его не вычислять:
m.erase(it);//ну нужен новый итератор

если же нужен новый итератор, то будь добр позаботиться об этом сам
Map и удаление элементов.
От: Wind Россия  
Дата: 27.10.04 21:41
Оценка:
у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически возникает задача удаления не нужных записей, причем таких записей может быть несколько и расположены они могут быть в произвольных местах. Алгоритм, который мне пришел в голову:
1) Перебираю каждый элемент списка на соответствие некоторым условиям
2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее

Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.

Вот такая ерунда.
Что псоветуете?
Re: Map и удаление элементов.
От: Sasparella США  
Дата: 27.10.04 21:49
Оценка:
Здравствуйте, Wind, Вы писали:


W>Вот такая ерунда.

W>Что псоветуете?

В похожей ситуайии я ничего умнее не придумал как пробежать по мепу, накопить во временном векторе ключи, соответсвующие структурам, подлежащим удалению, а потом пробежался по этому вектору, и сделал для каждого ключа в векторе map::erase(key).
Re[2]: Map и удаление элементов.
От: Sasparella США  
Дата: 27.10.04 21:52
Оценка:
То есть чтото типа такого

vector<key_type> vs;
for(it = map.begin(); it != map.end();++it)
{
  if (MustRemove((*it).second))
      vs.push_back((*it).first);
}

for(i = vs.begin(); i != vs.end();++i)
  map.erase(*i);
Re[2]: Map и удаление элементов.
От: Sasparella США  
Дата: 27.10.04 23:46
Оценка:
ПК>Только непосредственно удаленный.

Угу, согласен — но имхо на это полагаться не стоит — ибо потом контейнер может смениться (ну, например на тот же вектор) — и искать багу придется очень долго....
Re[3]: Map и удаление элементов.
От: e-Xecutor Россия  
Дата: 28.10.04 05:54
Оценка:
Здравствуйте, Sasparella, Вы писали:


ПК>>Только непосредственно удаленный.


S>Угу, согласен — но имхо на это полагаться не стоит — ибо потом контейнер может смениться (ну, например на тот же вектор) — и искать багу придется очень долго....


Как ты себе представляешь смену map на vector?
Re: Map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 06:09
Оценка:
Здравствуйте, Wind, Вы писали:

W>у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически возникает задача удаления не нужных записей, причем таких записей может быть несколько и расположены они могут быть в произвольных местах. Алгоритм, который мне пришел в голову:

W>1) Перебираю каждый элемент списка на соответствие некоторым условиям
W>2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее

W>Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.


W>Вот такая ерунда.

W>Что псоветуете?

используй map::erase(key)
С уважением,
Денис
Re: Map и удаление элементов.
От: Bell Россия  
Дата: 28.10.04 06:28
Оценка:
Здравствуйте, Wind, Вы писали:

Возможно, будет интересно почитать этот
Автор: maslukov
Дата: 06.10.04
топик.
Любите книгу — источник знаний (с) М.Горький
Re: map и удаление элементов.
От: itman itman.livejournal.com
Дата: 28.10.04 06:50
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

У меня вопро на засыпку:
 m.erase(i++);

и
 i = m.erase(i);

дадут одинаковые значения итератора? если да, то зачем, вообще, из ерейза что-то возвращать?

Удалено излишнее цитирование
Re[2]: Map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 06:55
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Wind, Вы писали:


B>Возможно, будет интересно почитать этот
Автор: maslukov
Дата: 06.10.04
топик.


Господа, поправте если ошибаюсь. При добавлении элемента в map элемент автоматически размещается в нужную позицию в соответствии с его ключом. Соответственно, элементы с одинаковым ключём должны размещаться рядом (при этом их может быть несколько).

m_map.erase(key) удалит все элементы с заданым ключом. Для чего нужен цикл, не понятно.
С уважением,
Денис
Re[2]: map и удаление элементов.
От: Bell Россия  
Дата: 28.10.04 06:57
Оценка:
Здравствуйте, itman, Вы писали:

I>Здравствуйте, Павел Кузнецов, Вы писали:


I>У меня вопро на засыпку:

I>
I> m.erase(i++);
I>

I>и
I>
I> i = m.erase(i);
I>

I>дадут одинаковые значения итератора?
Да, одинаковые.
I>если да, то зачем, вообще, из ерейза что-то возвращать?
Возможно, разработчики реализации STL для VC6 посчитали, что это имеет смысл (erse для вектора, например, возвращает итератор). По стандарту erase для map возвращает void.
Любите книгу — источник знаний (с) М.Горький
Re[3]: Map и удаление элементов.
От: Bell Россия  
Дата: 28.10.04 06:59
Оценка:
Здравствуйте, _wind_, Вы писали:

__>Здравствуйте, Bell, Вы писали:


B>>Здравствуйте, Wind, Вы писали:


B>>Возможно, будет интересно почитать этот
Автор: maslukov
Дата: 06.10.04
топик.


__>Господа, поправте если ошибаюсь. При добавлении элемента в map элемент автоматически размещается в нужную позицию в соответствии с его ключом. Соответственно, элементы с одинаковым ключём должны размещаться рядом (при этом их может быть несколько).


__>m_map.erase(key) удалит все элементы с заданым ключом. Для чего нужен цикл, не понятно.

map не сожержит дуприкатов ключей. Этим занимается multimap.
Любите книгу — источник знаний (с) М.Горький
Re[2]: map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 07:00
Оценка:
Здравствуйте, itman, Вы писали:

Удалено излишнее цитирование

ПК>>
ПК>>for (MyMap::iterator i = m.begin(), e = m.end(); i != e; /* здесь пусто */ )
ПК>>{
ПК>>   if ( . . . )
ПК>>     m.erase(i++);
ПК>>   else
ПК>>     ++i;
ПК>>}
ПК>>


"Скотт Майрес", Эффективное использование STL, страница 52
С уважением,
Денис
Re[4]: Map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 07:08
Оценка:
Здравствуйте, Bell, Вы писали:

Удалено излишнее цитирование

B>map не сожержит дуприкатов ключей. Этим занимается multimap.


ok
С уважением,
Денис
Re[3]: map и удаление элементов.
От: Аноним  
Дата: 28.10.04 07:10
Оценка:
Здравствуйте, _wind_, Вы писали:

__>Здравствуйте, itman, Вы писали:


I>>Здравствуйте, Павел Кузнецов, Вы писали:




ПК>>>
ПК>>>for (MyMap::iterator i = m.begin(), e = m.end(); i != e; /* здесь пусто */ )
ПК>>>{
ПК>>>   if ( . . . )
ПК>>>     m.erase(i++);
ПК>>>   else
ПК>>>     ++i;
ПК>>>}
ПК>>>


__>"Скотт Майрес", Эффективное использование STL, страница 52


тааак, открываю страницу 52 и что я вижу. есессно облом. когда посылаешь неплохо указать точное направление, (намёк издание, год, итд). впрочем, я догадываюсь, что ты хотел этим сказать. ну ладно, тогда правильее было бы переписать цикл так:
for (MyMap::iterator i = m.begin(), e = m.end(); i != e; /* здесь пусто */ )
{
 if ( . . . )
  i = m.erase(i);
 else
  ++i;
}

а теперь таки по поводу конструкции еще раз
m.erase(i++);

i++ возвращает копию итератора i, для erase, после чего наступает sequcne point и i инкрементируется. а уж потом делается erase. вроде все работает правильно, но совершенно неочевидно.
Re[4]: map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 07:20
Оценка:
Здравствуйте, Аноним, Вы писали:

Удалено излишнее цитирование

А>i++ возвращает копию итератора i, для erase, после чего наступает sequcne point и i инкрементируется. а уж потом делается erase. вроде все работает правильно, но совершенно неочевидно.


инкремент выполнится до начала выполнения функции, но после передачи параметра в функцию
С уважением,
Денис
Re[4]: Map и удаление элементов.
От: Alexey Chen Чили  
Дата: 28.10.04 07:24
Оценка:
Здравствуйте, e-Xecutor, Вы писали:

EX>Как ты себе представляешь смену map на vector?


Эээ, например так. (только это скорее замена multimap'у)

//вставка
cont.insert(lower_bound(cont.begin(),cont.end(),value,KeyLess()),value);

//поиск
pair<key_t,value_t> value = { key, value_t() };
cont_t::iterator i = lower_bound(cont.begin(),cont.end(),value,KeyLess());
if ( i != cont.end() && i->first == value.first ) // нашли

//удаление
pair<key_t,value_t> value = { key, value_t() };
pair<cont_t::iterator> e = equal_range(cont.begin(),cont.end(),value,KeyLess());
cont.remove(e.first,e.second);


Можно еще поиграть с определением KeyLess и работать только с ключом не создавая временной пары.
Re[4]: map и удаление элементов.
От: _wind_ Россия  
Дата: 28.10.04 07:28
Оценка:
Удалено излишнее цитирование

Кстати, когда-то давно встречался с задачей реализовать свою функцию void* malloc(size_t s)? Может кто-нибудь дать ссылки по теме? Ещё интересует реализация функций работы с кучей на базе массива. Хотелось бы просветиться прежде чем копаться в исходниках(malloc.c etc.) Tnx!
С уважением,
Денис
Re: Map и удаление элементов.
От: Кодт Россия  
Дата: 28.10.04 08:54
Оценка:
Здравствуйте, Wind, Вы писали:

W>Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.


Ты не прав.
Контейнеры list, set, map не переупорядочивают элементы при удалении/вставке, и не перемещают их в памяти.
То есть все итераторы (кроме относящихся к удаляемым) остаются валидными, а порядок следования сохраняется.

Таким образом, алгоритм удаления по условию будет выглядеть так
struct no_action
{
  template<class T> void operator()(T& t) const {}
};

template<class C, class P, class U>
void erase_if(C& cont, P pred, U utilize = no_action())
{
  C::iterator i=cont.begin(), j, e=cont.end();
  while(i!=e)
  {
    if(pred(*i))
    {
      j=i; // запомним итератор на текущий элемент
      ++i; // вскоре текущая позиция будет невалидна, поэтому спешим оттуда убраться
      utilize(*j);
      cont.erase(j);
    }
    else
      ++i;
  }
}

Другое дело, что может оказаться, что удаление элемента сопровождается добавлением других (из недр кода деструктора).
В этом случае, чтобы не зациклиться, может оказаться полезным двухфазное удаление: сперва получить список итераторов на удаляемые элементы, затем их всех перестрелять.
Перекуём баги на фичи!
Re: Map и удаление элементов.
От: TheBeard Россия  
Дата: 28.10.04 09:23
Оценка:
Вообще-то правильное удаление из map — это erase по ключу. Каков
критерий удаления? Определяется по содержимому СЛОЖНОЙ_СТРУКТУРЫ? Тогда
стоит попытаться формировать список ключей удаляемых элементов
(set<int>) и проходить по нему, удаляя соотв. элементы map.

Wind wrote:

> у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически

> возникает задача удаления не нужных записей, причем таких записей
> может быть несколько и расположены они могут быть в произвольных
> местах. Алгоритм, который мне пришел в голову: 1) Перебираю каждый
> элемент списка на соответствие некоторым условиям 2) Встретился
> элемент, который нужно удалить — удалил его и продолжил искать далее
Posted via RSDN NNTP Server 1.9 gamma
Re[2]: Map и удаление элементов.
От: Кодт Россия  
Дата: 28.10.04 09:42
Оценка:
Здравствуйте, TheBeard, Вы писали:

TB>Вообще-то правильное удаление из map — это erase по ключу. Каков

TB>критерий удаления? Определяется по содержимому СЛОЖНОЙ_СТРУКТУРЫ? Тогда
TB>стоит попытаться формировать список ключей удаляемых элементов
TB>(set<int>) и проходить по нему, удаляя соотв. элементы map.



В любом случае ты сперва тратишь O(N) времени на обход контейнера от begin() до end(), получая либо список итераторов, либо список ключей элементов, подлежащих удалению.
Затем ищешь каждый элемент за время O(1) если итератор, либо O(log N) если ключ — выполняется поиск.
После чего удаляешь элемент за O(log N) (перебалансировка).

Вопрос: зачем платить больше?
Перекуём баги на фичи!
Re[3]: Map и удаление элементов.
От: Аноним  
Дата: 28.10.04 11:25
Оценка:
Почему пропускться
на следующей итерации for выполнит it++
и все будет ок пример
мар:
1, объект
2, объект
3, объект
4, обьъект

на каком-то шаге
it = 3
it = map.erase(it); // после этого it =2
continue; // следующий элемент уже it =4 после того как for выполнит it ++








Здравствуйте, itman, Вы писали:

I>Здравствуйте, serega, Вы писали:


I>При этом будет регулярно пропускаться один элемент после удаляемого



S>>Привет

S>>в доке все написано

S>>Iterator map::erase (iterator Where)


S>>Return value:

S>>a bidirectional iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the map if no such element exists
S>>Следовательно делаем так

S>>
S>>for (it = map.begin();i != map.end();it++)
S>>{
S>>  if (условие)
S>>  {
S>>     it = map.erase(it); // it будет переброшен на первый верхний неизмененный елемент 
S>>  }
S>>}
S>>


S>>Успехов
Re[3]: Map и удаление элементов.
От: Кодт Россия  
Дата: 28.10.04 11:48
Оценка:
Здравствуйте, itman, Вы писали:

S>>в доке все написано


Эта дока называется MSDN и писана по Dinkumware STL, которая вот именно в этом месте отходит от Стандарта.
По Стандарту, void map::erase(map::iterator).
S>>for (it = map.begin();i != map.end();it++)
S>>{
S>>  if (условие)
S>>  {
S>>     it = map.erase(it); // it будет переброшен на первый верхний неизмененный елемент 
S>>  }
S>>}

В этом коде — ошибка. После того, как будет получен итератор на следующий за удаляемым элемент, мы на следующем шаге его инкрементируем.
Перекуём баги на фичи!
Re: map и удаление элементов.
От: Wind Россия  
Дата: 28.10.04 15:32
Оценка:
Здравствуйте, Павел Кузнецов,
MAP coll; //MAP - тайпдеф мепа.
MAP::iterator pos;

for(pos = coll.begin(); pos!=coll.end(); ++pos)
    if(pos->second==value)
        coll.erase(pos); //ошибка времени выполнения


Полсе вызова erase() для элемента, на который ссылается итератор, итератор становится не действительным. Любые попытки использовать этот итератор после удаления элемента без повторной инициализации — даже команда ++pos — приведет к непредсказуемым последствиям.


Согласен. Верю. Понимаю.

Правильный способ удаления элемента, на который ссылается итератор, выглядит так:


MAP coll; //MAP - тайпдеф мепа.
MAP::iterator pos;

for(pos = coll.begin(); pos!=coll.end(); )
    if(pos->second==value)
        coll.erase(pos++);
    else
        ++pos;

Код идентичен вашему.
Но лично я не понимаю в чем разница между примерами. Какая разница где итератор инкреминировать?
Re[2]: map и удаление элементов.
От: Анатолий Широков СССР  
Дата: 28.10.04 15:40
Оценка:
Посмотрите как реализована операция постинкремента:

T T::operator++(int)
{
   T temp(*this);
   ++(*this);
   return temp; (*)
}


А теперь взгляните на

coll.erase(pos++);


erase принимает старое значение pos (*) и именно старое значение (*) становится невалидным.
Re[2]: map и удаление элементов.
От: Кодт Россия  
Дата: 28.10.04 15:42
Оценка:
Здравствуйте, Wind, Вы писали:

W>Код идентичен вашему.


Нет, не идентичен.

W>Но лично я не понимаю в чем разница между примерами. Какая разница где итератор инкреминировать?


Не "где" а "когда" и "какой".
Давай заменим for() на эквивалентный while() — так будет понятнее
// твой код
pos = coll.begin();
while(pos != coll.end())
{
  if( to_be_deleted(*pos) )
    coll.erase(pos);
  ++pos; // если мы только что инвалидировали итератор (стерев элемент), то не можем его инкрементировать
}

// правильный код
pos = coll.begin();
while(pos != coll.end())
{
  if( to_be_deleted(*pos) )
    coll.erase(pos++);
  else
    ++pos;
}

// поскольку там фигурирует постинкремент, распишем его
pos = coll.begin();
while(pos != coll.end())
{
  if( to_be_deleted(*pos) )
  {
    temp = pos; ++pos; // вот что такое постинкремент
    coll.erase(temp); // тем самым мы никогда не будем иметь дело с инвалидным pos
  }
  else
    ++pos;
}
Перекуём баги на фичи!
Re[3]: map и удаление элементов.
От: Wind Россия  
Дата: 28.10.04 15:53
Оценка:
Здравствуйте, Анатолий Широков, Вы писали:

АШ>Посмотрите как реализована операция постинкремента:


АШ>А теперь взгляните на


АШ>erase принимает старое значение pos (*) и именно старое значение (*) становится невалидным.

Понял. Спасибо.
Re: Map и удаление элементов.
От: Carc Россия https://vk.com/gosha_mazov
Дата: 28.10.04 19:41
Оценка:
Здравствуйте, Wind, Вы писали:

W>у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически возникает задача удаления не нужных записей, причем таких записей может быть несколько и расположены они могут быть в произвольных местах. Алгоритм, который мне пришел в голову:

W>1) Перебираю каждый элемент списка на соответствие некоторым условиям
W>2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее

W>Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.


W>Вот такая ерунда.

W>Что псоветуете?
Вот буквально пару дней назад у меня именно такая задача стояла в дипломе.
Кстати теперь у меня много времени на диплом (в отличие от 4 дня назад) еще целый год, так что жду поздравлений

В целом все то же самое
std::map<int/*иногда свой ключ — некая struct*/, double>
т.е. значение всегда ВСТРОЕННЫЙ тип
Я пытался присобачить std::remove_if, насколько я понимаю std::remove_if переупорядочивает элементы по значению переданного ему предиката, и возвращает итератор, начиная с которого и до map::end() все элемены подлежат удалению
т.е. по сути надо потом позвать map::erase(returned_iterator, map::end())
что я и делал
НО! косяк был в следующем:
компилятор ругался на отсуствие MyMap::value_type::operator= т.е. он явно пытается какие то элементы переставить местами, и ругается что не может сделать присвоение для пары (MyMap::value_type это на самом деле pair<KEY, VALUE>)
причем для ключа я определил оператор присвоения, а значения в карте у меня встроенные...

В общем поскольку на тот момент было два дня до канадской границы, я действительно просто обходил map и перекладывал из него все что мне надо во временный map, а потом просто присваивал его.
Отсюда вопросы:
1) std::remove_if не умеет и не должен что ли работать с сортированными последовательностями (вроде как да, поскольку славные его перестановки должны видимо нарушать порядок в std::map)
2) Если все же они не должны работать, то как то очень подозрительно отсутствие встроенного алгоритма для именно std::map (в принципе тот же find же реализован в std::map, и логично было ожидать что если общий алгоритм имеет недостатки по сравнению с методом, то метод скорее будет реализован в контейнере). А отсуствие такого метода меня как-то наводило на мысль что все же std::remove_if можно научить работать с map!?!
3) и честно говоря так и не получилось у меня определить map::value_type::operator=
Что думаете коллеги?
Aml Pages Home
Re[2]: map и удаление элементов.
От: Павел Кузнецов  
Дата: 28.10.04 20:38
Оценка:
itman:

> У меня вопро на засыпку:

>
>  m.erase(i++);
>

> и
>
>  i = m.erase(i);
>

> дадут одинаковые значения итератора? если да, то зачем, вообще, из ерейза что-то возвращать?

У стандартного std::map<>::erase возвращаемое значение — void.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: Map и удаление элементов.
От: Павел Кузнецов  
Дата: 28.10.04 20:50
Оценка:
Carc:

0)

> компилятор ругался на отсуствие MyMap::value_type::operator= т.е. он явно пытается какие то элементы переставить местами, и ругается что не может сделать присвоение для пары (MyMap::value_type это на самом деле pair<KEY, VALUE>)


Потому что на самом деле в std::map хранятся std::pair<const Key, Value> — и это правильно (*)

> Отсюда вопросы:

> 1) std::remove_if не умеет и не должен что ли работать с сортированными последовательностями (вроде как да, поскольку славные его перестановки должны видимо нарушать порядок в std::map)

Верно.

> 2) Если все же они не должны работать, то как то очень подозрительно отсутствие встроенного алгоритма для именно std::map (в принципе тот же find же реализован в std::map, и логично было ожидать что если общий алгоритм имеет недостатки по сравнению с методом, то метод скорее будет реализован в контейнере). А отсуствие такого метода меня как-то наводило на мысль что все же std::remove_if можно научить работать с map!?!


Т.к. более эффективно, чем простой обход всех значений std::map, реализовать эту специализацию не выйдет, то смысла в ней не видно...

> 3) и честно говоря так и не получилось у меня определить map::value_type::operator=


goto 0)
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: map и удаление элементов.
От: Юнусов Булат Россия  
Дата: 28.10.04 21:09
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>У стандартного std::map<>::erase возвращаемое значение — void.


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

В этом смысле Ms просто пошла вперед
Re[4]: Map и удаление элементов.
От: Юнусов Булат Россия  
Дата: 28.10.04 21:23
Оценка:
Здравствуйте, Кодт, Вы писали:

В реализации метода erase (от ms) какие то контейнеры отдают тот же итератор что им дали, какие то (map к примеру) отдают инкрементнутый итератор.
Re[4]: map и удаление элементов.
От: Павел Кузнецов  
Дата: 28.10.04 22:50
Оценка:
Юнусов Булат,

> ПК>У стандартного std::map<>::erase возвращаемое значение — void.


> Вроде поднимался вопрос, чтобы переделать чтобы было как у всех контейнеров. И вроде как идею не зарубили совсем.


Насколько я помню последние обсуждения, то как раз наоборот: было решено этого не делать, т.к. для std::map/std::set инкремент итератора в некоторых случаях может оказываться достаточно дорогой операцией.
Posted via RSDN NNTP Server 1.9 gamma
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: Map и удаление элементов.
От: Dj.ValDen Украина http://ua.linkedin.com/in/dvalchuk
Дата: 29.10.04 06:48
Оценка:
Здравствуйте, Wind, Вы писали:

W>у меня есть std::map <int, СЛОЖНАЯ_СТРУКТУРА> a. Периодически возникает задача удаления не нужных записей, причем таких записей может быть несколько и расположены они могут быть в произвольных местах. Алгоритм, который мне пришел в голову:

W>1) Перебираю каждый элемент списка на соответствие некоторым условиям
W>2) Встретился элемент, который нужно удалить — удалил его и продолжил искать далее

W>Но вот незадача, после удаления элемента итераторы становятся не действительными, значит их нужно задать заново и с элемента .begin() заново начать поиск (заново, т.к. ни кто гарантий не дает, как будут располагаться элементы. Или я не прав?) Это потенциально долго, а на ключи полагаться нельзя, т.к. в момент работы алгоритма значения ключей не известны.


W>Вот такая ерунда.

W>Что псоветуете?

А так ?


    std::map <int,СЛОЖНАЯ_СТРУКТУРА>::iterator e;
    e = std::remove(a.begin(),a.end(),some_map_element); ///если на совпадение
    /// e = std::remove_if(a.begin(),a.end(),predicate(...));   ///если по условию
        a.erase(e,a.end());


:shuffle:
С уважением Denys Valchuk

IMHO чем больше мнений тем оптимальней выбор варианта... :)
Re[2]: Map и удаление элементов.
От: Bell Россия  
Дата: 29.10.04 06:52
Оценка:
Здравствуйте, Dj.ValDen, Вы писали:
DV>А так ?


DV>
DV>    std::map <int,СЛОЖНАЯ_СТРУКТУРА>::iterator e;
DV>    e = std::remove(a.begin(),a.end(),some_map_element); ///если на совпадение
DV>    /// e = std::remove_if(a.begin(),a.end(),predicate(...));   ///если по условию
DV>        a.erase(e,a.end());
DV>


DV>


Алгоритмы remove/remove_if не работают с ассоциативными контейнерами.
Это только что повторили здесь
Автор: Carc
Дата: 28.10.04
Любите книгу — источник знаний (с) М.Горький
Re[2]: Map и удаление элементов.
От: Dj.ValDen Украина http://ua.linkedin.com/in/dvalchuk
Дата: 29.10.04 07:21
Оценка:
DV>
DV>    std::map <int,СЛОЖНАЯ_СТРУКТУРА>::iterator e;
DV>    e = std::remove(a.begin(),a.end(),some_map_element); ///если на совпадение
DV>    /// e = std::remove_if(a.begin(),a.end(),predicate(...));   ///если по условию
DV>        a.erase(e,a.end());
DV>


oops
sorry
я не прав...
С уважением Denys Valchuk

IMHO чем больше мнений тем оптимальней выбор варианта... :)
Re[5]: map и удаление элементов.
От: Кодт Россия  
Дата: 29.10.04 07:46
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> ПК>У стандартного std::map<>::erase возвращаемое значение — void.


>> Вроде поднимался вопрос, чтобы переделать чтобы было как у всех контейнеров. И вроде как идею не зарубили совсем.


ПК>Насколько я помню последние обсуждения, то как раз наоборот: было решено этого не делать, т.к. для std::map/std::set инкремент итератора в некоторых случаях может оказываться достаточно дорогой операцией.


А это не спасёт: добыча итератора на следующий за удалённым элемент в дереве — такая же дорогостоящая, как и простой инкремент. Ну может быть, чуть-чуть дешевле, если после перебалансировки расстояние между элементами в дереве сократилось.
Ну а если говорить точно, то время инкремента — O(log N).
Перекуём баги на фичи!
Re: map и удаление элементов.
От: Аноним  
Дата: 03.11.04 09:43
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>for (MyMap::iterator i = m.begin(), e = m.end(); i != e; /* здесь пусто */ )

ПК>{
ПК> if ( . . . )
ПК> m.erase(i++);
ПК> else
ПК> ++i;
ПК>}

А возможно применение данного алгоритма в том случае, когда удаление одного элемента может потянуть за собой удаление еще нескольких ???
К примеру:


iterator i=begin();

while( i != end() ) 
{
     if(i->second->must_die()) {
          delete i->second; // В деструкторе могут удаляться еще несколько объектов map'a ( вызывается erase( key ) )
          P::erase( i++ );
     } else {
          ++i;
     }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.