Reputation: 387
I need to erase elements from a vector based on their value, I've tried the idiom erase-remove_if but the condition for the item to be erased is not so simple, I've tried something like
map<string, TLorentzVector> map_jets
vector<pair<string,double> > jets_pt
for( vector<pair<string,double> >::iterator it1 = jets_pt.begin(); it1 != jets_pt.end(); ){
if( fabs(map_jets[it1->first].PseudoRapidity()) > 2.5 )
jets_pt.erase(it1);
but I get a segmentation violation
when jets_pt
has size = 1.
The whole program takes data of an experiment and loops over, the map keeps track of the name of the event and the associated variable I need, while the vector stores the string of the map and a value that I need to keep track of.
I want to delete from the vector those value which does'n satisfy a few condition
if( fabs(map_jets[it1->first].PseudoRapidity()) > 2.5 )
jets_pt.erase(it1);
if( map_jets[it->first].DeltaR(map_leps["lep1"]) < 0.4 && map_jets[it->first].DeltaR(map_leps["lep2"]) < 0.4 && map_jets[it->first].DeltaR(map_leps["lep3"]) )
jets_pt.erase(it);
if( jets_emfr[k] > 0.9 )
jets_pt.erase(it);
Upvotes: 0
Views: 283
Reputation: 20211
I assume in your real code you actually call operator++
for the iterator somewhere in the loop. However you still have the problem that erase invalidates the iterator, so you would need to do
it = jets_pt.erase(it1);
However the remove_if - erase
is really a much more suitable solution here
I ould remmend something like the following:
struct remove_functor
{
map<string, TLorentzVector>& map_jets;
map<...>& map_leps;
remove_functor(map<string, TLorentzVector>& m_jets, map<...>& m_leps): map_jets(m_jets), map_leps(m_leps)
{}
bool operator()(const pair<string,double>& p)
{
return (fabs(map_jets[p.first].PseudoRapidity()) > 2.5)
|| ((map_jets[p.first].DeltaR(map_leps["lep1"]) < 0.4)
&& (map_jets[p.first].DeltaR(map_leps["lep2"]) < 0.4)
&& (map_jets[p.first].DeltaR(map_leps["lep3"]));
}
}
Then you can simply use
jets_pt.erase(remove_if(jets_pt.begin(), jets_pt.end(), remove_functor(map_jets, map_leps)), jets_pt.end());
Of course in c++0x you can simply use a lambda function:
auto predicate = [&](const pair<string, double>& p) {bool operator()(const pair<string,double>& p)
{
return (fabs(map_jets[p.first].PseudoRapidity()) > 2.5)
|| ((map_jets[p.first].DeltaR(map_leps["lep1"]) < 0.4)
&& (map_jets[p.first].DeltaR(map_leps["lep2"]) < 0.4)
&& (map_jets[p.first].DeltaR(map_leps["lep3"]));
};
jets_pt.erase(remove_if(jets_pt.begin(), jets_pt.end(), predicate), jets_pt.end());
predicate = [&](...){...};
creates an functor (by means of lambda syntax), which captures all used variables by reference (so map_jets, map_leps,...
, indicated by the [&]
) which can be used for the remove_if
. auto
means that the compiler should infer the type of the variable (since we don't have a name for the type generated by the compiler for this lambda).
Upvotes: 1
Reputation: 1813
Try the following (approximative c++11, I don't have access to a c++11 conforming compiler on this computer):
jets_pt.erase(
remove_if(
jets_pt.begin(),
jets_pt.end(),
[&](const pair<string,double> &p) {
return fabs(map_jets[p.first].PseudoRapidity()) > 2.5;
}),
jets_pt.end());
Basically, you want to erase from the iterator returned by remove_if up to the end of the vector. You may edit the predicate to remove_if as needed.
Upvotes: 1
Reputation: 5386
Do not erase entries while iterating! You invalidate your loop constraints.
Upvotes: 0
Reputation: 94549
This sounds like a job for the std::remove_if
algorithm, which can be used to remove elements matching a given predicate from a container.
Something like this ought to work:
bool myPredicate( pair<string, double> element ) {
return fabs(map_jets[elem.first].PseudoRapidity()) > 2.5
|| (map_jets[elem.first].DeltaR(map_leps["lep1"]) < 0.4 && ... )
|| ...
}
jets_pt.erase( remove_if( jets_pt.begin(), jets_pt.end(), myPredicate ),
jets_pt.end() );
Upvotes: 2