.[ ČeskéHry.cz ].
Odstranění prvků vyhovujících predikátu z STL map

 
odeslat nové téma   Odpovědět na téma    Obsah fóra České-Hry.cz -> C / C++
Zobrazit předchozí téma :: Zobrazit následující téma  
Autor Zpráva
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 30. říjen 2008, 16:22:26    Předmět: Odstranění prvků vyhovujících predikátu z STL map Odpovědět s citátem

Zdravím, dneska jsem narazil na problém s touto "triviální" úlohou. Mám std::map<int, MujObjekt>. Chtěl bych z ní vyhodit všechny záznamy, kde instance mého objektu splňuje jistý predikát. Jak na to ve standardním C++ ?

Jeden přístup by byl asi takovýto:
kód:

for (map<...>::iterator i = x.begin(); i != x.end(); ) {
  if (i->second splňuje podmínku) {
    i = x.erase(i->first);
  } else {
    i++;
  }
}


Jenže to funguje jen v MS C++, jinde map::erase nevrací nic.

OK, tak jsem našel funkci remove_if v <algorithm>. Jenže ta zas nejde zkompilovat kvůli absenci operator = v std::pair<>. A kdo ví, jestli vůbec bude na map<> fungovat, když je to spíš strom než sekvence.

A nic jiného mě nenapadá, je tu někdo chytřejší?
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
MD



Založen: 29. 07. 2007
Příspěvky: 437
Bydliště: Praha

PříspěvekZaslal: 30. říjen 2008, 17:20:07    Předmět: Odpovědět s citátem

Jen tak, co me v rychlosti napada: Nemel bys tam dat tomu erase primo iterator (tedy i) a ne klic? Pak by to melo smazat a vratit iterator na nasledujici prvek.

Edit: Nejsem si vubec jist jestli se to da takhle v cyklu prochazet a mazat. Ten strom se muze pri deletu preorganizovat a pak by ti mohly nektere objekty utect (dostat se pred iterator a ty bys je preskocil). Pokud tohle nekdo vite, tak me to docela zajima. V MSDN u erase samozrejme nic nepisou.

Edit2: MSDN: Note that this return type does not conform to the C++ standard.
_________________
- play with objects - www.krkal.org -
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 30. říjen 2008, 17:32:23    Předmět: Odpovědět s citátem

To je stejná situace:
http://www.cplusplus.com/reference/stl/map/erase.html

EDIT: V MSDN píšou, že ta jejich verze erase vrací iterátor za vymazaný prvek, tak by to mohlo jít.
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Marek



Založen: 28. 07. 2007
Příspěvky: 1782
Bydliště: Velká Morava

PříspěvekZaslal: 30. říjen 2008, 17:44:47    Předmět: Odpovědět s citátem

Linked list se mi tady zdá vhodnější. Jinak ten erase s iterátorem by měl být celkem snadno implementovatelný. Především se mi nelíbí to, že ten tvůj algoritmus má složitost O(nlogn) (erase s klíčem), když by mohl mít jen O(n) (erase s iterátorem). V případě, že parametr je opravdu klíč, pak bys musel udělat find na hledanej prvek s klíčem, udělat ++iterator na další prvek a smazat ten nalezený. Pokud mažeš přímo podle iterátoru, stačí si jen zapamatovat následující prvek. Mazání během procházení tady nevadí, pokud se to udělá opatrně. Kód na požadované erase:

kód:
template<typename Key, typename T>
typename std::map<Key, T>::iterator map_erase(std::map<Key, T> &m, typename std::map<Key, T>::iterator it)
{
    typename std::map<Key, T>::iterator next = it;
    ++next;
    m.erase(it); // O(1)
    // m.erase(it->first); // alternativa v O(logn), nicmene zbytecna prace navic
    return next;
}


Pozn.: Když se podíváš na implementaci funkci map::erase v MS STL, najdeš tam přesně tohle.
_________________
AMD Open Source Graphics Driver Developer
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 30. říjen 2008, 17:54:57    Předmět: Odpovědět s citátem

No tu map<> tam asi z nějakého důvodů mám, žejo Smile Tahle operace se dělá jednou za uherský rok, takže mě rychlost tolik netíží. A je pravda, že udělat it + 1 před smazáním mě mohlo napadnout (jinak ano, iterátor mám k dispozici, do toho kódu nahoře jsem to napsal blbě). Pokud map<> používá standardní binární vyhledávací strom s uspořádáním podle <, potom by přeskládání nemělo vadit, protože pořadí prvků je pořád stejné.
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
MD



Založen: 29. 07. 2007
Příspěvky: 437
Bydliště: Praha

PříspěvekZaslal: 30. říjen 2008, 17:59:59    Předmět: Odpovědět s citátem

operace plus ++ na iteratoru jde na nejblizsi vyzsi prvek (jsou serazene), je to tak?
Pak by preskakovani prvku bylo nelogicke.
_________________
- play with objects - www.krkal.org -
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Tringi



Založen: 28. 07. 2007
Příspěvky: 290

PříspěvekZaslal: 30. říjen 2008, 18:36:28    Předmět: Odpovědět s citátem

Z dokumentace:
Standard C++ 23.1.4.1, odstavec 8 napsal:
The insert members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.

Dokumentace SGI STL napsal:
Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.


To znamená, klidně to nech takto:
kód:
for (map<...>::iterator i = x.begin(); i != x.end(); ) {
    if (i->second splňuje podmínku) {
        x.erase(i++);
    } else
        ++i;
}

_________________
WWW | GitHub | TW
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Quiark



Založen: 29. 07. 2007
Příspěvky: 816
Bydliště: Chlívek 401

PříspěvekZaslal: 30. říjen 2008, 19:08:59    Předmět: Odpovědět s citátem

Super Smile
_________________
Mám strach
Návrat nahoru
Zobrazit informace o autorovi Odeslat soukromou zprávu Zobrazit autorovi WWW stránky
Zobrazit příspěvky z předchozích:   
odeslat nové téma   Odpovědět na téma    Obsah fóra České-Hry.cz -> C / C++ Časy uváděny v GMT + 1 hodina
Strana 1 z 1

 
Přejdi na:  
Nemůžete odesílat nové téma do tohoto fóra
Nemůžete odpovídat na témata v tomto fóru
Nemůžete upravovat své příspěvky v tomto fóru
Nemůžete mazat své příspěvky v tomto fóru
Nemůžete hlasovat v tomto fóru


Powered by phpBB © 2001, 2005 phpBB Group


Vzhled udelal powermac
Styl "vykraden" z phpBB stylu MonkiDream - upraveno by rezna