Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

STL suppression d'un element suivant critere

21 réponses
Avatar
Thierry
Bonjour,

je veux supprimer un element d'un vecteur suivant un critere.

Le code type serait
for (it = vec.begin(); it != vec.end(); it++)
if (it.value == 1)
it = vec.erase(it);

mais dans ce cas erase fait passer it a l'elem suivant et est reincrementé
dans la boucle, donc on saute un element.

Sur le net y'a des solutions comme ça:

for (it = vec.begin(); it != vec.end();) {

if (it.value == 1) {
it = vec.erase(it);
}
else it++;
}

Mais ca match pas avec mon code qui a différences branches et je dois
utiliser un flag pour savoir si je doit incrementer l'iterateur ou pas.

Pas tres élégant.

Y'a pas de façon de faire plus propre ??


--
Vainqueur du 1er WSOFRJCP

10 réponses

1 2 3
Avatar
Marc Boyer
Le 13-05-2011, Thierry a écrit :
Marc écrivait
news:iqjbfa$2e9$:
Thierry wrote:
J'ai bien vu:
http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-
vector.html
mais std::unique doit se baser sur l'operateur == pour supprimer les
elements, et ça correspond pas a ce que je veux, puisque je veux
garder les elements strictement identiques.



unique, comme tous les algos de la STL, peut prendre un foncteur comme
argument supplémentaire, au lieu d'utiliser ==.



Ok, la callback "foncteur" a deux arguments item1 et item2.
Quand je retourne true il supprimera item1 ou item2 ??
Je ne trouve pas dans la doc.



Ca n'a pas l'air spécifié. Puisque tu veux garder celui ayant
le troisième champ le plus grand, tu peux peut-être affecter cette
valeur aux deux.

Marc Boyer
--
En prenant aux 10% des francais les plus riches 12% de leurs revenus,
on pourrait doubler les revenus des 10% les plus pauvres.
http://www.inegalites.fr/spip.php?article1&id_mot0
Avatar
Thierry
Marc écrivait
news:iqjbfa$2e9$:

Thierry wrote:

J'ai bien vu:
http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-
vector.html mais std::unique doit se baser sur l'operateur == pour
supprimer les elements, et ça correspond pas a ce que je veux,
puisque je veux garder les elements strictement identiques.



unique, comme tous les algos de la STL, peut prendre un foncteur comme
argument supplémentaire, au lieu d'utiliser ==.



Ca ne marche pas: il va appeller une unique fois la fonction pour comparer
2 item A et B, et supprimer A ou B selon soit choix si je retourne true,
alors que je veux que la callback soit appellée 2 fois, (A, B) et (B, A) et
choisir l'element a supprimer.

--
Vainqueur du 1er WSOFRJCP
Avatar
Thierry
Marc Boyer écrivait
news:iqjet3$vt9$:

Ok, la callback "foncteur" a deux arguments item1 et item2.
Quand je retourne true il supprimera item1 ou item2 ??
Je ne trouve pas dans la doc.



Ca n'a pas l'air spécifié. Puisque tu veux garder celui ayant
le troisième champ le plus grand, tu peux peut-être affecter cette
valeur aux deux.



Bien vu, même si ce champs n'est pas forcement censé être modifié en dehors
de la classe. Pas tres grave.
je teste ça.

--
Vainqueur du 1er WSOFRJCP
Avatar
Marc
Marc Boyer wrote:

Le 13-05-2011, Thierry a écrit :
Marc écrivait
unique, comme tous les algos de la STL, peut prendre un foncteur comme
argument supplémentaire, au lieu d'utiliser ==.



Ok, la callback "foncteur" a deux arguments item1 et item2.
Quand je retourne true il supprimera item1 ou item2 ??
Je ne trouve pas dans la doc.



Ca n'a pas l'air spécifié.



"For a nonempty range, eliminates all but the first element from every
consecutive group of equivalent elements referred to by the iterator i
in the range [first + 1,last) for which the following conditions hold:
[...] pred(*(i - 1), *i) != false."

Donc il supprime item2, toujours.
Avatar
Thierry
Marc écrivait
news:iqjbfa$2e9$:

Thierry wrote:

J'ai bien vu:
http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-
vector.html mais std::unique doit se baser sur l'operateur == pour
supprimer les elements, et ça correspond pas a ce que je veux,
puisque je veux garder les elements strictement identiques.



unique, comme tous les algos de la STL, peut prendre un foncteur comme
argument supplémentaire, au lieu d'utiliser ==.



A propos de unique: il a toujours l'air d'etre utilisé avec sort avant.
Pour des raisons de perf ??

Je crois que je vais profiter de ma call back de sort pour marquer les
items a supprimer, puis faire une passe avec une simple boucle pour les
supprimer reellement.

--
Vainqueur du 1er WSOFRJCP
Avatar
Marc
Thierry wrote:

A propos de unique: il a toujours l'air d'etre utilisé avec sort avant.
Pour des raisons de perf ??



Unique ne supprime un élément que s'il est égal à celui juste avant.
C'est donc plus utile si l'ensemble est trié. Il n'essaie pas du tout
de rendre les éléments uniques globalement.

Je crois que je vais profiter de ma call back de sort pour marquer les
items a supprimer, puis faire une passe avec une simple boucle pour les
supprimer reellement.



C'est une possibilité. S'il y a effectivement un appel à sort avant
celui à unique, il est facile de donner à sort une fonction qui place
les éléments dans le bon ordre pour que unique fasse ce qu'il faut.
C'est dur de ne pas faire un peu de travail en double (vive la
commande unix sort et son option -u ;-).
Avatar
Thierry
Marc Boyer écrivait
news:iqjet3$vt9$:

Le 13-05-2011, Thierry a écrit :
Marc écrivait
news:iqjbfa$2e9$:
Thierry wrote:
J'ai bien vu:
http://learningcppisfun.blogspot.com/2008/04/remove-duplicates-from-
vector.html mais std::unique doit se baser sur l'operateur == pour
supprimer les elements, et ça correspond pas a ce que je veux,
puisque je veux garder les elements strictement identiques.



unique, comme tous les algos de la STL, peut prendre un foncteur comme
argument supplémentaire, au lieu d'utiliser ==.



Ok, la callback "foncteur" a deux arguments item1 et item2.
Quand je retourne true il supprimera item1 ou item2 ??
Je ne trouve pas dans la doc.



Ca n'a pas l'air spécifié. Puisque tu veux garder celui ayant
le troisième champ le plus grand, tu peux peut-être affecter cette
valeur aux deux.



Bizarre, je suis obligé d'appeller 2 fois la fonction
vec.erase(unique(vec.begin, vec.end, callback), vec.end) pour supprimer
tous les "doublons"...

--
Vainqueur du 1er WSOFRJCP
Avatar
Fabien LE LEZ
On 13 May 2011 12:57:48 GMT, Thierry :

En fait c'est un peu plus complique et je dois supprimer des "doublons" si
ils ont les 2 premiers champs identiques mais que le 3 eme est inférieur a
l'autre.



Si tu tries ton tableau avant, avec le tri qui va bien, l'élément à
supprimer sera toujours le second de chaque couple.

Ainsi, après tri, ton tableau ressemble à :

a x 17
a x 16
b y 5
b y 3
b y 1

Et unique() va supprimer les doublons, ne gardant que
a x 17
b y 5
Avatar
Thierry
Fabien LE LEZ écrivait
news::

On 13 May 2011 12:57:48 GMT, Thierry :

En fait c'est un peu plus complique et je dois supprimer des
"doublons" si ils ont les 2 premiers champs identiques mais que le 3
eme est inférieur a l'autre.



Si tu tries ton tableau avant, avec le tri qui va bien, l'élément à
supprimer sera toujours le second de chaque couple.



Ok, ca doit venir de là mon probleme
<news:. Je ne tri que sur les 2
premiers champs.

Merci.

--
Vainqueur du 1er WSOFRJCP
Avatar
James Kanze
On May 13, 3:19 pm, Jean-Marc Bourguet wrote:
Thierry writes:
> Jean-Marc Bourguet écrivait
>news::

>> Thierry writes:

>>> je veux supprimer un element d'un vecteur suivant un critere.

>> bool a_effacer(int i)
>> {
>> return i == 42;
>> }

>> vec.erase(std::remove(vec.begin(), vec.end(), 42));

>> vec.erase(std::remove_if(vec.begin(), vec.end(), a_effacer));

> En fait c'est un peu plus complique et je dois supprimer des
> "doublons" si ils ont les 2 premiers champs identiques mais
> que le 3 eme est inférieur a l'autre.

Comme ceci? (Avec 2 champs plutot que 3, mais l'idee y est)

class AEffacer
{
public:
AEffacer(int i, int j) : first(i), second(j) {}
bool operator()(std::pair<int, int> const& p) {
return p.first == first && p.second < second;
}
private:
int first, second;
};

vec.erase(std::remove_if(vec.begin(), vec.end(), AEffacer(4, 2)), vec.end ());



Si j'ai bien compris, il ne veut pas comparer à des valeurs
constantes, mais à d'autres valeurs dans le vecteur. Ce qui fait
que remove_if ne convient pas trop.

En fait, son problème dépend en premier lieu de si le vecteur
est trié ou non. S'il est trié, il suffit qu'il compare avec
l'élément précédant, et unique, avec un comparateur qui
convient, pourrait fair l'affaire. Sinon, je ne crois pas qu'il
y a un algorithme standard qui fait l'affaire ; pour chaque
élément, il faudrait qu'il fasse un find. (Ou sinon, il fait
une copy du vecteur, sur lequel il fait std::find_if dans le
prédicat de remove_if.)

--
James Kanze
1 2 3