For example, I good 2 vector, say vector current, vector to_delete. Is there some good way to delete elements which appear both in current.
Here is my way to do it. I guess it not looks good. So please help me out. Thank you.
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <double> current;
current.push_bac开发者_如何学Pythonk(1.1);
current.push_back(2.1);
current.push_back(3.1);
current.push_back(4.1);
current.push_back(5.1);
current.push_back(6.1);
current.push_back(7.1);
current.push_back(8.1);
vector <double> to_delete;
to_delete.push_back(2.1);
to_delete.push_back(5.1);
for(int i = 0;i<to_delete.size();i++){
int loc = -1;
for(int j = 0; j < current.size();j++)
{
if(current[j]==to_delete[i]){
loc = j;
break;
}
}
if(loc >= 0){
current.erase(current.begin()+loc);
}
}
for(int i = 0;i < current.size();i++){
cout << current[i]<< endl;
}
}
Probably the simplest way is to construct a new vector using std::set_difference
(both vectors have to be sorted for this to work):
std::vector<double> diff;
std::set_difference(current.begin(), current.end(),
to_delete.begin(), to_delete.end(),
std::back_inserter(diff));
What's wrong with something like:
std::vector<double>::iterator iter
= std::find_first_of( current.begin(), current.end(),
to_delete.begin(), to_delete.end() );
while ( iter != current.end() ) {
iter = std::find_first_of( current.erase( iter ), current.end(),
to_delete.begin(), to_delete.end() );
}
Alternatively, you can define a predicate:
template <typename Container>
class IsElementOf
{
Container const* m_container;
public:
IsElementOf(Container const& container)
: m_container(&container)
{
}
bool operator()( typename Container::value_type const& v ) const
{
return std::find( m_container->begin(),
m_container->end(),
v )
!= m_container->end();
}
};
template <typename Container>
inline IsElementOf<Container>
isElementOf( Container const& container )
{
return IsElementOf<Container>(container);
}
and use std::remove_if:
current.erase(
std::remove_if( current.begin(), current.end(),
isElementOf( to_delete ) ),
current.end() );
(This is really only a valid proposal if you have to do this sort of thing in a number of different places. Or if you can use boost::bind to generate the IsElementOf in place, but that's difficult, because the compiler won't know where to start when it comes to figuring out the type, so you'll have to explicitly specify it somewhere.)
You could use std::find()
instead of a manual loop to find the position of the element that should be deleted.
std::vector<double>::iterator del =
std::find(current.begin(), current.end(), to_delete[i]);
if (del != current.end())
current.erase(del);
First you should note that in your specific example that x.1
is NOT fully representable in a base two floating point format and that attempting to compare those values may result in inequality due to the code the compiler generates even if it appears that it should work.
Next, is vector
really the right kind of container if you need arbitrary deletion like that? Did you consider using set
or multiset
instead?
If you need a random-access container then you can use the set_difference
method suggested by @Space_C0wb0y or use std::remove
:
for(int i = 0;i<to_delete.size();i++)
{
current.erase(std::remove(current.begin(), current.end(), to_delete[i]), current.end());
}
Assuming n = current.size()
and m = to_delete.size()
, If it's already sorted, set_difference
should be linear. If it is not sorted, it would be O(n log n) + O(m log m)
. The remove approach would be O(m n)
精彩评论