This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Delete Duplicate Entries in a vector
I need to delete double entries in C++ STL vectors. An important point is that the order of elements in the resulting vector must be equivalent to the order in the input vector. Is there an algorithm (e.g. in stl, boost) which would do this?
There are two possible cases here: either the vector is already sorted or it isn't.
If it is, std::erase and std::unique can easily solve this as shown in the other answers.
If it isn't then you can do achieve the goal with
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
but there's a problem in that predicate is not trivial to specify: it's a function that accepts one argument (the value to consider) and it needs to answer the question "is there any equal value earlier in the vector?". Since you aren't told where exactly in the vector the supplied argument is, that means you 'd have to keep quite a bit of manual state to be able to answer this.
A convenient option here would be to use an std::set to do some of the heavy lifting:
std::set<decltype(v)::value_type> set(v.begin(), v.end());
v.erase(
std::remove_if(
v.begin(),
v.end(),
[&set] (decltype(v)::value_type item) { return !set.erase(item); }),
v.end());
What this does is prepopulate an std::set with the values in the vector and then check if an item has been seen before by seeing if it has been removed from the set. This way the result will retain only the first item from each set of items that compare equal in the input.
See it in action.
If your vector is not sorted and you thus cannot just use std::unique (and likewise cannot sort it which would destroy your order), you can use something like this function (using C++11 lambdas):
template<typename FwdIt> FwdIt unordered_unique(FwdIt first, FwdIt last)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
std::set<value_type> unique;
return std::remove_if(first, last, [&unique](const value_type &arg) {
return !unique.insert(arg).second; });
}
Which can be invoke using the usual erase-romve-idiom:
v.erase(unordered_unique(v.begin(), v.end()), v.end());
Of course you can also use C++11's std::unordered_set instead of a std::set (for hashable types, of course) to get away from O(n log n) in average case.
How about std::unique?
auto firstDup = std::unique(myvector.begin(), myvector.end());
Use next:
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
Related
This question already has answers here:
Erasing elements from a vector
(6 answers)
Closed 8 years ago.
Here my code. I want remove from vector all elements with successfully called method 'release'.
bool foo::release()
{
return true;
}
// ...
vector<foo> vec;
// ...
remove_if(vec.begin(), vec.end(), [](foo & f) { return f.release() == true; });
// ...
But remove_if not deleting all elements from vector vec. How remove_if works?
std::remove_if re-arranges the elements of the vector such that the elements you want to keep are in the range [vec.begin(), return_iterator) (note the partially open range). So you need to call std::vector::erase to make sure the vector contains only the desired elements. This is called the erase-remove idiom:
auto it = remove_if(vec.begin(),
vec.end(),
[](foo & f) { return f.release() == true; });
vec.erase(it, vec.end());
Here, I have split it into two lines for clarity, but it is often seen as a one-liner.
std::remove and std::remove_if do not actually remove anything but just give you an iterator by which you can then erase elements using the appropriate member function of whatever container you use. In std::vector's case, erase.
I invite you to read this old article from Scott Meyers: "My Most Important C++ Aha! Moments...Ever":
It was thus with considerable shock and a feeling of betrayal that I discovered that applying remove to a container never changes the number of elements in the container, not even if you ask it to remove everything. Fraud! Deceit! False advertising!
Because the remove_if algorithm operates on a range of elements denoted by two forward iterators, it has no knowledge of the underlying container or collection.
Thus, no elements are actually removed from the container. Rather, all elements which don't fit the remove criteria are brought together to the front of the range, in the same relative order.
The remaining elements are left in a valid, but unspecified, state. When this is done, remove returns an iterator pointing one element past the last unremoved element.
To actually eliminate elements from the container, remove should be combined with the container's erase member function (hence the name "erase-remove idiom").
How to use remove-erase idiom for removing empty vectors in a vector?
Erasing elements from a vector
See http://en.wikipedia.org/wiki/Erase-remove_idiom
std::remove_if doesn't actually obliterate erase the elements. What it does is move the elements that satisfies the criteria into the end of the range. It then returns an iterator to the first element of the removed (which are actually just moved) elements. It is on you then to erase that range from the container.
vector<foo> vec;
auto remove_start = remove_if(vec.begin(), vec.end(), [](foo & f) { return f.release() == true; });
vec.erase(remove_start, vec.end());
or
vec.erase(remove_if(vec.begin(), vec.end(),
[](foo & f) { return f.release() == true; }),
vec.end());
Could this be the worst named function in the STL? (rhetorical question)
std::remove_copy_if() doesn't actually appear to do any removing. As best I can tell, it behaves more like copy_if_not.
The negation is a bit confusing, but can be worked around with std::not1(), however I might be misunderstanding something as I cannot fathom what this function has to do with removing - am I missing something?
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Editing to add an example so readers are less confused.
The following program appears to leave the input range (V1) untouched:
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using std::cout;
using std::endl;
int main (void)
{
std::vector<int> V1, V2;
V1.push_back(-2);
V1.push_back(0);
V1.push_back(-1);
V1.push_back(0);
V1.push_back(1);
V1.push_back(2);
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::remove_copy_if(
V1.begin(),
V1.end(),
std::back_inserter(V2),
std::bind2nd(std::less<int>(), 0));
std::copy(V2.begin(), V2.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
std::copy(V1.begin(), V1.end(), std::ostream_iterator<int>(cout, " "));
cout << endl;
}
It outputs:
-2 0 -1 0 1 2
0 0 1 2
-2 0 -1 0 1 2
I was expecting so see something like:
-2 0 -1 0 1 2
0 0 1 2
0 0 1 2 ? ? ?
Where ? could be any value. But I was surprised to see that the input range was untouched, & that the return value is not able to be used with (in this case) std::vector::erase(). (The return value is an output iterator.)
Could this be the worst named function in the STL?
A bit of background information: in the standard library (or the original STL), there are three concepts, the containers, the iterators into those containers and algorithms that are applied to the iterators. Iterators serve as a cursor and accessor into the elements of a range but do not have a reference to the container (as mentioned before, there might not even be an underlying container).
This separation has the nice feature that you can apply algorithms to ranges of elements that do not belong to a container (consider iterator adaptors like std::istream_iterator or std::ostream_iterator) or that, belonging to a container do not consider all elements (std::sort( v.begin(), v.begin()+v.size()/2 ) to short the first half of the container).
The negative side is that, because the algorithm (and the iterator) don't really know of the container, they cannot really modify it, they can only modify the stored elements (which is what they can access). Mutating algorithms, like std::remove or std::remove_if work on this premise: they overwrite elements that don't match the condition effectively removing them from the container, but they do not modify the container, only the contained values, that is up to the caller in a second step of the erase-remove idiom:
v.erase( std::remove_if( v.begin(), v.end(), pred ),
v.end() );
Further more, for mutating algorithms (those that perform changes), like std::remove there is a non-mutating version named by adding copy to the name: std::remove_copy_if. None of the XXXcopyYYY algorithms are considered to change the input sequence (although they can if you use aliasing iterators).
While this is really no excuse for the naming of std::remove_copy_if, I hope that it helps understanding what an algorithm does given its name: remove_if will modify contents of the range and yield a range for which all elements that match the predicate have been removed (the returned range is that formed by the first argument to the algorithm to the returned iterator). std::remove_copy_if does the same, but rather than modifying the underlying sequence, it creates a copy of the sequence in which those elements matching the predicate have been removed. That is, all *copy* algorithms are equivalent to copy and then apply the original algorithm (note that the equivalence is logical, std::remove_copy_if only requires an OutputIterator, which means that it could not possibly copy and then walk the copied range applying std::remove_if.
The same line of reasoning can be applied to other mutating algorithms: reverse reverses the values (remember, iterators don't access the container) in the range, reverse_copy copies the elements in the range to separate range in the reverse order.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
There is no such algorithm in the STL, but it could be easily implementable:
template <typename FIterator, typename OIterator, typename Pred>
FIterator splice_if( FIterator first, FIterator last, OIterator out, Pred p )
{
FIterator result = first;
for ( ; first != last; ++first ) {
if ( p( *first ) ) {
*result++ = *first;
} else {
*out++ = *first;
}
}
return result;
}
is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
The closest thing I can think of is std::stable_partition:
std::vector<int> v;
// ...
auto it = std::stable_partition(v.begin(), v.end(), pick_the_good_elements);
std::vector<int> w(std::make_move_iter(it), std::make_move_iter(v.end()));
v.erase(it, v.end());
Now v will contain the "good" elements, and w will contain the "bad" elements.
If not, is there an STL algorithm for conditionally removing (moving?) elements from a container & putting them in another container?
Not really. The idea is that the modifying algorithms are allowed to "move" (not in the C++ sense of the word) elements in a container around but cannot change the length of the container. So the remove algorithms could be called prepare_for_removal.
By the way, C++11 provides std::copy_if, which allows you to copy selected elements from one container to another without playing funny logic games with remove_copy_if.
You are right, that is what it does... std::remove_copy_if copies the vector, removing anything that matches the pred.
std::remove_if ... removes on condition (or rather, shuffles things around).
I agree that remove is not the best name for this family of functions.
But as Luc said, there's a reason for it working the way it does, and the GoTW item that he mentions explains how it works. remove_if works exactly the same way as remove - which is what you would expect.
You might also want to read this Wikibooks article.
The standard way to remove certain elements from a vector in C++ is the remove/erase idiom. However, the predicate passed to remove_if only takes the vector element under consideration as an argument. Is there a good STL way to do this if the predicate is conditional on other elements of the array?
To give a concrete example, consider removing all duplicates of a number immediately following it. Here the condition for removing the n-th element is conditional on the (n-1)-th element.
Before: 11234555111333
After: 1234513
There's a standard algorithm for this. std::unique will remove the elements that are duplicates of those preceding them (actually, just like remove_if it reorganizes the container so that the elements to be removed are gathered at the end of it).
Example on a std::string for simplicity:
#include <string>
#include <iostream>
#include <algorithm>
int main()
{
std::string str = "11234555111333";
str.erase(std::unique(str.begin(), str.end()), str.end());
std::cout << str; // 1234513
}
Others mentioned std::unique already, for your specific example. Boost.Range has the adjacent_filtered adaptor, which passes both the current and the next element in the range to your predicate and is, thanks to the predicate, applicable to a larger range of problems. Boost.Range however also has the uniqued adaptor.
Another possibility would be to simply keep a reference to the range, which is easy to do with a lambda in C++11:
std::vector<T> v;
v.erase(std::remove_if(v.begin(), v.end(),
[&](T const& x){
// use v, with std::find for example
}), v.end());
In my opinion, there will be easier to use simple traversal algorithm(via for) rather then use std::bind. Of course, with std::bind you can use other functions and predicates(which depends on previous elements). But in your example, you can do it via simple std::unique.
This question already has answers here:
How to find out if an item is present in a std::vector?
(18 answers)
Closed 10 years ago.
Is there any built in function which tells me that my vector contains a certain element or not
e.g.
std::vector<string> v;
v.push_back("abc");
v.push_back("xyz");
if (v.contains("abc")) // I am looking for one such feature, is there any
// such function or i need to loop through whole vector?
You can use std::find as follows:
if (std::find(v.begin(), v.end(), "abc") != v.end())
{
// Element in vector.
}
To be able to use std::find: include <algorithm>.
If your container only contains unique values, consider using std::set instead. It allows querying of set membership with logarithmic complexity.
std::set<std::string> s;
s.insert("abc");
s.insert("xyz");
if (s.find("abc") != s.end()) { ...
If your vector is kept sorted, use std::binary_search, it offers logarithmic complexity as well.
If all else fails, fall back to std::find, which is a simple linear search.
In C++11, you can use std::any_of instead.
An example to find if there is any zero in the array:
std::array<int,3> foo = {0,1,-1};
if ( std::any_of(foo.begin(), foo.end(), [](int i){return i==0;}) )
std::cout << "zero found...";
it's in <algorithm> and called std::find.
std::find().
This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Checking value exist in a std::map - C++
How to traverse a stl map/vector/list/etc?
Hello,
Is it possible to search for specific value in std::map, not knowing the key? I know I could iterate over whole map, and compare values, but it is possible to do using a function from std algorithms?
Well, you could use std::find_if :
int main()
{
typedef std::map<int, std::string> my_map;
my_map m;
m.insert(std::make_pair(0, "zero"));
m.insert(std::make_pair(1, "one"));
m.insert(std::make_pair(2, "two"));
const std::string s("one");
const my_map::const_iterator it = std::find_if(
m.begin(), m.end(), boost::bind(&my_map::value_type::second, _1) == s
);
}
But that's just slightly better than a hand-crafted loop : it's still O(n).
You could use Boost.Bimap if you want to index on values as well as keys. Without this or similar, this will have to be done by brute force (=> scan the map by hand).
Boost.Bimap is a bidirectional maps
library for C++. With Boost.Bimap you
can create associative containers in
which both types can be used as key.
Will this help? STL find_if
You need to have some sort of predicate, either a function pointer or an object with operator() implemented. Said predicate should take just one parameter.
There are (awkward) ways to do this using standard functions (e.g., std::find_if), but these still involve iterating over the whole map. Boost.Bimap will provide efficient indexing in both directions, and you can go even further with Boost.Multi-Index.