OVH Cloud OVH Cloud

[map] enlever une clé

14 réponses
Avatar
Fanny Chevalier
Bonjour,

J'ai une map map <int, vector <int> > _voisins;
qui me permet d'avoir acces a l'ensemble des voisins d'un element.
Lorsque l'element disparait, je voudrait supprimer la case contenant
l'element :

lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
je ne veux plus que mon iterateur s'arrete sur la case 1.

Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
l'element 1 est toujours dans la map.
Si je fais _voisins.erase(1), ca a le meme effet...

Comment faire pour supprimer la cle 1 ?

Merci par avance.

Fanny

10 réponses

1 2
Avatar
Loïc Joly
Fanny Chevalier wrote:

Bonjour,

J'ai une map map <int, vector <int> > _voisins;
qui me permet d'avoir acces a l'ensemble des voisins d'un element.
Lorsque l'element disparait, je voudrait supprimer la case contenant
l'element :

lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
je ne veux plus que mon iterateur s'arrete sur la case 1.

Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
l'element 1 est toujours dans la map.


Normal, là tu dit de prendre le vector correspondant à 1 et de le
remettre à 0.

Si je fais _voisins.erase(1), ca a le meme effet...


Moins normal.

Chez moi, le code suivant fait ce qu'il faut :
#include <iostream>
#include <map>
#include <vector>

using namespace std;
typedef map<int, vector <int> > Voisins;

void affiche(Voisins const &v)
{
for (Voisins::const_iterator vi = v.begin(); vi != v.end(); ++vi)
{
cout << vi->first << " : ";
for (vector<int>::const_iterator it = vi->second.begin() ;
it != vi->second.end();
++it)
{
cout << *it << " ";
}
cout << endl;
}
}

int main(int argc, char *argv[])
{
Voisins voisin;
voisin[0].push_back(1);
voisin[0].push_back(2);
voisin[0].push_back(3);
voisin[1].push_back(0);
voisin[1].push_back(2);
voisin[1].push_back(3);
voisin[2].push_back(0);
voisin[3].push_back(1);
affiche(voisin);
voisin.erase(1);
cout << "après : " << endl;
affiche(voisin);
return 0;
}

Quel compilateur utilises tu ? Et quelle STL ?

--
Loïc

Avatar
Gabriel Dos Reis
Fanny Chevalier writes:

[...]

| > Quel compilateur utilises tu ? Et quelle STL ?
| >
| J'utilise emacs 21.3.1 et je ne sais pas comment on voit quelle STL
| j'utilise...

Si tu utilises GCC, regarde ce que donne la commande

g++ -v

-- Gaby
Avatar
Gabriel Dos Reis
Fanny Chevalier writes:

| Bonjour,
|
| J'ai une map map <int, vector <int> > _voisins;
| qui me permet d'avoir acces a l'ensemble des voisins d'un element.
| Lorsque l'element disparait, je voudrait supprimer la case contenant
| l'element :

Qu'entends-tu par « lorsque l'élément disparaît » ? Tu veux l'enlever
complètement du tableau ? Utilise par exemple .erase() avec la valeur
de la clé.

| lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
| je ne veux plus que mon iterateur s'arrete sur la case 1.

OK.

| Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
| l'element 1 est toujours dans la map.

C'est normal : Tu lui dis de faire l''opération de (vector<int>) sur
la valeur correspond à la clé 1, mais cette opération (de vector<int>)
ne détruit pas l'entrée (de map<>) correspondant à 1.

| Si je fais _voisins.erase(1), ca a le meme effet...

Là, je ne suis pas d'accord. Comment te rends-tu compte que cela a le
même effet ? Tu utilises operator[] ou .find()? Il faut utiliser
find(), autrement tu vas ajouter des entrées sans le vouloir (c'est
une des propriétés subtiles de operator[] pour map<>).

| Comment faire pour supprimer la cle 1 ?

_voisins.erase(1);

-- Gaby
Avatar
Gabriel Dos Reis
Fanny Chevalier writes:

| Loïc Joly wrote:
|
| > Fanny Chevalier wrote:
| >
| >> Bonjour,
| >>
| >> J'ai une map map <int, vector <int> > _voisins;
| >> qui me permet d'avoir acces a l'ensemble des voisins d'un element.
| >> Lorsque l'element disparait, je voudrait supprimer la case contenant
| >> l'element :
| >>
| >> lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
| >> je ne veux plus que mon iterateur s'arrete sur la case 1.
| >>
| >> Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
| >> l'element 1 est toujours dans la map.
| >
| >
| > Normal, là tu dit de prendre le vector correspondant à 1 et de le
| > remettre à 0.
| >
| >> Si je fais _voisins.erase(1), ca a le meme effet...
| >
| >
| > Moins normal.
| >
| > Chez moi, le code suivant fait ce qu'il faut :
| > #include <iostream>
| > #include <map>
| > #include <vector>
| >
| > using namespace std;
| > typedef map<int, vector <int> > Voisins;
| >
| > void affiche(Voisins const &v)
| > {
| > for (Voisins::const_iterator vi = v.begin(); vi != v.end(); ++vi)
| > {
| > cout << vi->first << " : ";
| > for (vector<int>::const_iterator it = vi->second.begin() ;
| > it != vi->second.end();
| > ++it)
| > {
| > cout << *it << " ";
| > }
| > cout << endl;
| > }
| > }
| >
| > int main(int argc, char *argv[])
| > {
| > Voisins voisin;
| > voisin[0].push_back(1);
| > voisin[0].push_back(2);
| > voisin[0].push_back(3);
| > voisin[1].push_back(0);
| > voisin[1].push_back(2);
| > voisin[1].push_back(3);
| > voisin[2].push_back(0);
| > voisin[3].push_back(1);
| > affiche(voisin);
| > voisin.erase(1);
| > cout << "après : " << endl;
| > affiche(voisin);
| > return 0;
| > }
| >
| > Quel compilateur utilises tu ? Et quelle STL ?
| >
| Ton code me donne ce qu'il faut aussi...
| D'ou ca vient? J'utilise pas de typedef, et mon iterateur est pas tout
| a fait pareil :
| map <int, vector <int> >::iterator it;

c'est pas ça qui change. Je me demande comment tu récupères ton
itérateur.

| et puis en realite je travaille avec une map <unsigned char, vector
| <unsigned char> >
| mais ca, je pense pas que ca change quelque chose...

C'est exact.

| Autre detail, la map _voisins est un attribut de ma classe :
| private :
| map <unsigned char, vector <unsigned char> > _voisins;

Cela ne devrait rien changer -- même si l'utilisation de typedef dans
ce cas serait plutôt recommandée.

-- Gaby
Avatar
Fanny Chevalier
Loïc Joly wrote:

Fanny Chevalier wrote:

Bonjour,

J'ai une map map <int, vector <int> > _voisins;
qui me permet d'avoir acces a l'ensemble des voisins d'un element.
Lorsque l'element disparait, je voudrait supprimer la case contenant
l'element :

lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
je ne veux plus que mon iterateur s'arrete sur la case 1.

Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
l'element 1 est toujours dans la map.



Normal, là tu dit de prendre le vector correspondant à 1 et de le
remettre à 0.

Si je fais _voisins.erase(1), ca a le meme effet...



Moins normal.

Chez moi, le code suivant fait ce qu'il faut :
#include <iostream>
#include <map>
#include <vector>

using namespace std;
typedef map<int, vector <int> > Voisins;

void affiche(Voisins const &v)
{
for (Voisins::const_iterator vi = v.begin(); vi != v.end(); ++vi)
{
cout << vi->first << " : ";
for (vector<int>::const_iterator it = vi->second.begin() ;
it != vi->second.end();
++it)
{
cout << *it << " ";
}
cout << endl;
}
}

int main(int argc, char *argv[])
{
Voisins voisin;
voisin[0].push_back(1);
voisin[0].push_back(2);
voisin[0].push_back(3);
voisin[1].push_back(0);
voisin[1].push_back(2);
voisin[1].push_back(3);
voisin[2].push_back(0);
voisin[3].push_back(1);
affiche(voisin);
voisin.erase(1);
cout << "après : " << endl;
affiche(voisin);
return 0;
}

Quel compilateur utilises tu ? Et quelle STL ?

J'utilise emacs 21.3.1 et je ne sais pas comment on voit quelle STL

j'utilise...


Avatar
Fanny Chevalier
Si tu utilises GCC, regarde ce que donne la commande

g++ -v

-- Gaby


gcc version 3.3.2 20031022 (Red Hat Linux 3.3.2-1)


Avatar
Fanny Chevalier
Loïc Joly wrote:

Fanny Chevalier wrote:

Bonjour,

J'ai une map map <int, vector <int> > _voisins;
qui me permet d'avoir acces a l'ensemble des voisins d'un element.
Lorsque l'element disparait, je voudrait supprimer la case contenant
l'element :

lorsque je supprime l'element 1, dont les voisins etaient 4,6,8
je ne veux plus que mon iterateur s'arrete sur la case 1.

Si je fais _voisins[1].clear(), je n'ai plus la liste des voisins mais
l'element 1 est toujours dans la map.



Normal, là tu dit de prendre le vector correspondant à 1 et de le
remettre à 0.

Si je fais _voisins.erase(1), ca a le meme effet...



Moins normal.

Chez moi, le code suivant fait ce qu'il faut :
#include <iostream>
#include <map>
#include <vector>

using namespace std;
typedef map<int, vector <int> > Voisins;

void affiche(Voisins const &v)
{
for (Voisins::const_iterator vi = v.begin(); vi != v.end(); ++vi)
{
cout << vi->first << " : ";
for (vector<int>::const_iterator it = vi->second.begin() ;
it != vi->second.end();
++it)
{
cout << *it << " ";
}
cout << endl;
}
}

int main(int argc, char *argv[])
{
Voisins voisin;
voisin[0].push_back(1);
voisin[0].push_back(2);
voisin[0].push_back(3);
voisin[1].push_back(0);
voisin[1].push_back(2);
voisin[1].push_back(3);
voisin[2].push_back(0);
voisin[3].push_back(1);
affiche(voisin);
voisin.erase(1);
cout << "après : " << endl;
affiche(voisin);
return 0;
}

Quel compilateur utilises tu ? Et quelle STL ?

Ton code me donne ce qu'il faut aussi...

D'ou ca vient? J'utilise pas de typedef, et mon iterateur est pas tout a
fait pareil :
map <int, vector <int> >::iterator it;
et puis en realite je travaille avec une map <unsigned char, vector
<unsigned char> >
mais ca, je pense pas que ca change quelque chose...
Autre detail, la map _voisins est un attribut de ma classe :
private :
map <unsigned char, vector <unsigned char> > _voisins;


Avatar
Fanny Chevalier
Voici mon code :
J'appelle :

afficheVoisins(_nodesNeighborhood);
editNeighborhood(26, 97); // en unsigned char bien sur...
afficheVoisins(_nodesNeighborhood);

void afficheVoisins(map <unsigned char, vector <unsigned char> > const &v)
{
for (map <unsigned char, vector <unsigned char> >::const_iterator vi
= v.begin();
vi != v.end(); ++vi)
{
cout << (int) vi->first << " : ";
for (vector<unsigned char>::const_iterator it = vi->second.begin() ;
it != vi->second.end();
++it)
cout << (int) *it << " ";
cout << endl;
}
}

void
Graph::editNeighborhood(unsigned char labelToDelete, unsigned char
labelToKeep)
{
map<unsigned char, vector <unsigned char> >::const_iterator it;
for (it = _nodesNeighborhood.begin() ; it != _nodesNeighborhood.end()
; ++it)
{
/* 1er cas, on remplace les voisins des regions qui n'ont pas bouge */
if ((*it).first != labelToDelete)
{
bool already = false; // l'etiquette de la region +grande
y est deja
bool isPresent = false; // l'etiquette de la region +petite
y est
unsigned int index; // l'indice du tableau ou apparait
l'etiquette double


for (unsigned int nb = 0 ; nb <
_nodesNeighborhood[(*it).first].size() ; nb++)
{
if(_nodesNeighborhood[(*it).first][nb] == labelToKeep)
already = true;
else if (_nodesNeighborhood[(*it).first][nb] == labelToDelete)
{
isPresent = true;
_nodesNeighborhood[(*it).first][nb] = labelToKeep;
index = nb;

// Si la fusion engendre un voisin identique a l'element il
faudra le supprimer
if (labelToKeep == (*it).first)
already = true;
}
}
// Si le voisin existait deja et que la fusion engendre une
duplication
// des voisins, il faut en supprimer un par decalage des valeurs
if (already && isPresent)
{
for (unsigned int u = index ; u <
_nodesNeighborhood[(*it).first].size() - 1 ; u++)
_nodesNeighborhood[(*it).first][u] =
_nodesNeighborhood[(*it).first][u+1];
_nodesNeighborhood[(*it).first].pop_back();
}
}


/* 2eme cas, on ajoute a la region fusionnee de plus grande aire
les voisins de l'autre */
else
{
map <unsigned char, bool> isPresent; // pour savoir si on
duplique les voisins
isPresent.clear();

for (unsigned int nb = 0 ; nb <
_nodesNeighborhood[labelToKeep].size() ; nb++)
isPresent[_nodesNeighborhood[labelToKeep][nb]] = true;

for (unsigned int nb = 0 ; nb <
_nodesNeighborhood[labelToDelete].size() ; nb++)
{
if (_nodesNeighborhood[labelToDelete][nb] != labelToKeep)
cout << "Il est different de " << (int) labelToKeep << endl;

if(!isPresent[_nodesNeighborhood[labelToDelete][nb]]
&& (_nodesNeighborhood[labelToDelete][nb] != labelToKeep))

_nodesNeighborhood[labelToKeep].push_back(_nodesNeighborhood[labelToDelete][nb]);
}
}
}
cout << "Je veux effacer la case " << (int) labelToDelete << endl;
_nodesNeighborhood.erase(labelToDelete);
}


Et j'obtiens :
2 : 42
26 : 97
42 : 2 70
70 : 42 85 97 218 222
85 : 70 186
97 : 70 26
186 : 85
218 : 70 240
222 : 70
240 : 218

Je veux effacer la case 97
on a fusionne les noeuds 26 et 97 !!!
2 : 42
26 : 70
42 : 2 70
70 : 42 85 26 218 222
85 : 70 186
97 :
186 : 85
218 : 70 240
222 : 70
240 : 218


Moi je voudrais qu'il aille plus sur 97 au deuxieme coup...
Avatar
Fanny Chevalier
Là, je ne suis pas d'accord. Comment te rends-tu compte que cela a le
même effet ? Tu utilises operator[] ou .find()? Il faut utiliser
find(), autrement tu vas ajouter des entrées sans le vouloir (c'est
une des propriétés subtiles de operator[] pour map<>).


Je fais afficher tous les elements, quand je met _voisisns.erase(97)

j'ai ce resultat :
2 : 42
26 : 70
42 : 2 70
70 : 42 85 26 218 222
85 : 70 186
97 :
186 : 85
218 : 70 240
222 : 70
240 : 218

et quand je le met pas :
2 : 42
26 : 70
42 : 2 70
70 : 42 85 26 218 222
85 : 70 186
97 : 70 26
186 : 85
218 : 70 240
222 : 70
240 : 218

Avatar
drkm
Fanny Chevalier writes:

Voici mon code :


[...]

Étrange. J'ai réalisé quelques modifications sur ton code, mais il
s'agit principalement de modifications de style, ou de réagancement de
code, sans réelle modification de l'algorithme. J'ai ensuite testé
avec un sous-ensemble des valeurs que tu donnais, et j'obtiens bien la
bonne réponse.

Es-tu certaine d'avoir donné le code réel. J'ai remarqué par
exemple :

void Graph::editNeighborhood(
unsigned char labelToDelete ,
unsigned char labelToKeep
) ;
editNeighborhood( 26 , 97 ) ;

Et j'obtiens :
[...]
Je veux effacer la case 97

alors qu'il devrait s'agir de la 26 ...

Voici le résultat chez moi :

~> g++ -o fclcxx2 fclcxx2.cc -Wall -ansi -pedantic
~> ./fclcxx2
2 : 42
26 : 97
42 : 2 70
70 : 42 97
97 : 26 70
186 : 42
Je veux effacer la case 26
2 : 42
42 : 2 70
70 : 42 97
97 : 70
186 : 42
~> cat fclcxx2.cc
#include <iostream>
#include <map>
#include <ostream>
#include <vector>

typedef unsigned char MyType ;
typedef std::vector< MyType > MyVect ;
typedef std::map< MyType , MyVect > MyMap ;

MyMap nodesNeighborhood ;

void editNeighborhood( MyType labelToDelete , MyType labelToKeep ) ;
void afficheVoisins( MyMap const & v ) ;


void init( MyMap & m )
{
typedef MyMap::value_type MyValue ;

MyVect v2 ;
v2.push_back( 42 ) ;
m.insert( MyValue( 2 , v2 ) ) ;
MyVect v26 ;
v26.push_back( 97 ) ;
m.insert( MyValue( 26 , v26 ) ) ;
MyVect v42 ;
v42.push_back( 2 ) ;
v42.push_back( 70 ) ;
m.insert( MyValue( 42 , v42 ) ) ;
MyVect v70 ;
v70.push_back( 42 ) ;
v70.push_back( 97 ) ;
m.insert( MyValue( 70 , v70 ) ) ;
MyVect v97 ;
v97.push_back( 26 ) ;
v97.push_back( 70 ) ;
m.insert( MyValue( 97 , v97 ) ) ;
MyVect v186 ;
v186.push_back( 42 ) ;
m.insert( MyValue( 186 , v186 ) ) ;
}

int main()
{
init( nodesNeighborhood ) ;

afficheVoisins( nodesNeighborhood ) ;
editNeighborhood( 26 , 97 ) ;
afficheVoisins( nodesNeighborhood ) ;
}

void afficheVoisins( MyMap const & v )
{
for ( MyMap::const_iterator vi = v.begin() ; vi != v.end() ; ++ vi )
{
std::cout << static_cast< int >( vi->first ) << " : " ;
for ( MyVect::const_iterator it = vi->second.begin() ;
it != vi->second.end() ;
++ it ) {
std::cout << static_cast< int >( * it ) << " " ;
}
std::cout << std::endl ;
}
}

void editNeighborhood( MyType labelToDelete , MyType labelToKeep )
{
for ( MyMap::iterator it = nodesNeighborhood.begin() ;
it != nodesNeighborhood.end() ;
++ it )
{
if ( it->first != labelToDelete )
{
bool already = false ;
bool isPresent = false ;
MyVect::iterator to_erase ;

for ( MyVect::iterator
target = it->second.begin() ,
end = it->second.end() ;
target != end ;
++ target )
{
if ( * target == labelToKeep ) {
already = true ;
}
else if ( * target == labelToDelete ) {
isPresent = true ;
* target = labelToKeep ;
to_erase = target ;
if ( it->first == labelToKeep ) {
already = true ;
}
}
}
if ( already && isPresent ) {
it->second.erase( to_erase ) ;
}
}
else
{
typedef MyVect::size_type MySize ;

std::map< MyType , bool > isPresent ;
MyVect & vect_to_keep = nodesNeighborhood[ labelToKeep ] ;
MyVect & vect_to_delete = nodesNeighborhood[ labelToDelete ] ;

for ( MySize nb = 0 ; nb < vect_to_keep.size() ; ++ nb ) {
isPresent[ vect_to_keep[ nb ] ] = true ;
}
for ( MySize nb = 0 ; nb < vect_to_delete.size() ; ++ nb ) {
MyType to_delete = vect_to_delete[ nb ] ;
if ( to_delete != labelToKeep ) {
std::cout
<< "Il est different de "
<< static_cast< int >( labelToKeep )
<< std::endl ;
}
if ( ! isPresent[ to_delete ] && to_delete != labelToKeep ) {
vect_to_keep.push_back( to_delete ) ;
}
}
}
}

std::cout
<< "Je veux effacer la case "
<< static_cast< int >( labelToDelete )
<< std::endl ;
nodesNeighborhood.erase( labelToDelete ) ;
}

--drkm

1 2