If I have
vector<T> list
Where each element in the list is unique, what's the easiest way of deleting an element provided that I don't know if it's in the list or not? I don't know the index of the element and I don't care if it's not on the list.
You could use the Erase-remove idiom for std::vector
Quote:
std::vector<int> v;
// fill it up somehow
v.erase(std::remove(v.begin(), v.end(), 99), v.end());
// really remove all elements with value 99
Or, if you're sure, that it is unique, just iterate through the vector and erase the found element. Something like:
for( std::vector<T>::iterator iter = v.begin(); iter != v.end(); ++iter )
{
if( *iter == VALUE )
{
v.erase( iter );
break;
}
}
Based on Kiril's answer, you can use this function in your code :
template<typename T>
inline void remove(vector<T> & v, const T & item)
{
v.erase(std::remove(v.begin(), v.end(), item), v.end());
}
And use it like this
remove(myVector, anItem);
If occurrences are unique, then you should be using std::set<T>, not std::vector<T>.
This has the added benefit of an erase member function, which does what you want.
See how using the correct container for the job provides you with more expressive tools?
#include <set>
#include <iostream>
int main()
{
std::set<int> notAList{1,2,3,4,5};
for (auto el : notAList)
std::cout << el << ' ';
std::cout << '\n';
notAList.erase(4);
for (auto el : notAList)
std::cout << el << ' ';
std::cout << '\n';
}
// 1 2 3 4 5
// 1 2 3 5
Live demo
From c++20
//LIKE YOU MENTIONED EACH ELEMENT IS UNIQUE
std::vector<int> v = { 2,4,6,8,10 };
//C++20 UNIFORM ERASE FUNCTION (REMOVE_ERASE IDIOM IN ONE FUNCTION)
std::erase(v, 8); //REMOVES 8 FROM VECTOR
Now try
std::erase(v, 12);
Nothing will happen, the vector remains intact.
Related
I would like to know if it is possible to access the elements of std::vector<std::vector<int>> via iterators: I cannot understand why this won't compile:
#include<vector>
#include<iostream>
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
// to access the single vector
auto it = vec.begin() ;
// to access the element of the vector
auto iit = it.begin() ;
Here the error I get:
prova.cpp: In function ‘int main()’:
prova.cpp:10:15: error: ‘class __gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int> > >’ has no member named ‘begin’
10 | auto iit = it.begin() ;
You can get an iterator to the inner elements from a reference to the inner vector. An iterator is not a reference to the element, but you have to dereference it. Change this:
// to access the element of the vector
auto iit = it.begin() ;
To
auto iit = it->begin();
Don't overcomplicate stuff. You iterate a vector like this:
std::vector<T> vect;
for (auto it = vect.begin(); it != vect.end(); ++it) {
auto& element = *it;
// element is a reference to the element in the vector
}
or with a range based loop:
for (auto& element : vect) {
// element is a reference to the element in the vector
}
It really never gets more complicated than that.
When you have a nested vector and you want to iterate elements of the inner vectors you just need to first get elements of the outer vector, then elements of the inner ones:
std::vector<std::vector<T>> vect2;
for (auto& inner_vector : vect2) {
// inner_vector is reference to element of vect2
for (auto& element : inner_vector) {
// element is reference to element of inner vector
}
}
auto iit = it.begin();
doesn't compile because it is an iterator, not a vector. You should use the overloaded value-of operator to get the vector pointed to by it.
auto iit = (*it).begin();
Then you can use the iterators as normal.
You can also use range-based for-loops:
for(auto &row : vec) {
for(auto &col : row) {
// do things
}
}
Iterators in particularly random access iterators simulate the behavior of pointers.
For example if you have an object of a class like:
struct A
{
int x;
} a = { 10 };
and a pointer to the object:
A *pa = &a;
then to access data members of the object using the pointer you need to write for example either:
std::cout << pa->x << '\n';
or:
std::cout << ( *pa ).x << '\n';
So consider this declaration:
auto it = vec.begin();
as a declaration of a pointer.
So using this iterator you can gets iterators of stored vectors like
auto iit1 = it->begin() ;
auto iit2 = ( ++it )->begin();
Using this approach you can write nested for loops to output the vector.
Here is a demonstration program:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
for ( auto it = vec.cbegin(); it != vec.cend(); ++it )
{
for ( auto iit = it->cbegin(); iit != it->cend(); ++iit )
{
std::cout << *iit << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is:
1 2
3 4
I have used member functions cbegin and cend instead of begin and end to show that the vector is not being changed within the loops.
To do the same it is simpler to use the range-based for loop. For example:
#include <iostream>
#include <vector>
int main()
{
std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
for (const auto &v : vec )
{
for ( const auto &item :v )
{
std::cout << item << ' ';
}
std::cout << '\n';
}
std::cout << '\n';
return 0;
}
The program output is the same as shown above.
In the range-based for loop the compiler itself dereferences the iterators instead of you.
If you really want to use iterators the following code would do the job.
#include<vector>
#include<iostream>
int main()
{
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
for (auto it = vec.cbegin(); it != vec.cend(); ++it)
{
for (auto iit = it->cbegin(); iit != it->cend(); ++iit)
{
std::cout << "elem: " << *iit << "\n";
}
}
}
Otherwise, by all means use ranged for loops.
#include<vector>
#include<iostream>
int main()
{
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
for (const auto& inner_vec : vec)
{
for (const auto& elem : inner_vec)
{
std::cout << "elem: " << elem << '\n';
}
}
}
According to Cplusplus
An iterator is any object that, pointing to some element in a range of
elements (such as an array or a container)
vector <int> v = {0,1,2};
auto it = v.begin();
// it is a iterator pointing to the first element of the vector
// To access the first element, we will use *it
cout << *it; // will output 0
// Notice how * is used to get the value where it points at
In your case, vec is a vector of vectors. Where each element of vec is itself a vector. Each element of v defined in the above code snippet was an int.
std::vector<std::vector<int>> vec {{1,2},{3,4}} ;
// it is an iterator pointing to the elements of vec
// Notice that it points to the elements of vec
// Each element of vec is a vector itself
// So it "points" to a vector
auto it = vec.begin() ;
// to access the element of the vector
//auto iit = it.begin() ;
// To access the elements (which are int) of the vector, you need to use:
auto iit = (*it).begin();
// *it is the value where it points to (which is basically the first vector )
Another way to iterate over vec would be to use for each loop
for(auto v : vec)
{
for(int a : v)
{
cout<<a;
// a is an integer
}
}
I need to iterate through the keys of a map, but looking ahead to future keys. For example:
map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << "\n";
//is the next element equal to 3?
auto next = it++;
std::cout << "equals 3" << next==3 << std::endl
}
but sometimes I don't want to see the next element (n+1), maybe I want to see the n+10 element, etc. How do I do this? If my list has 100 elements, and I arrive at element 99, then 99+10 is gonna break evrything. Is there a way to test if my iterator can achieve n+10?
The best solution I thougth of is to keep track of an index i and see if I can call it + 10 (that is, if i+10<mapSize). Bus is there a more elegant way? Maybe testing if the n+10 iterator exists or something?
Map does not sound like the appropiate data type for your use case. Try switching to a container that supports random access
I think that your are looking for something like std::advance (Please see here), but with an additional check, if the advance operation was past the end or not.
We can use a small lambda to do this kind of check. Since it uses only an increment operation, it should work for all type of containers.
Please see the following example to illustrate the function:
#include <iostream>
#include <map>
#include <iterator>
using Type = std::map<int, int>;
using TypeIter = Type::iterator;
int main() {
// Lambda to advance a container iterator and check, if that was possible
auto advanceAndCheck = [](const Type& t, const TypeIter& ti, size_t advance) -> std::pair<bool, TypeIter>
{ TypeIter i{ ti }; while ((i != t.end()) && (advance--)) ++i; return { i != t.end(), i }; };
// Test data
Type m{ {1,1}, {2,2}, {3,3}, {4,4}, {5,5} , {6,6} };
// Iterate over container
for (TypeIter it = m.begin(); it != m.end(); ++it) {
// Show some values
std::cout << it->first << "\n";
// Test
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 1);
if (OK && itn->first == 3) std::cout << "The next Element is 3\n";
}
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 5);
if (OK && itn->first == 6) std::cout << "The 5th next Element is 6\n";
}
}
}
I tried to remove duplicate elements from a vector by a function vectorremove, using the function remove from the library of algorithms, but it does not work:
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
void vectorremove(vector<string> v)
{
for (vector<string>::iterator it = v.begin(); it != v.end(); ++it)
{
vector<string>::iterator end = remove(it + 1, v.end(), *it);
v.erase(end, v.end());
}
}
int main()
{
vector<string> vect;
string x;
while (cin >> x)
{
vect.push_back(x);
}
vectorremove(vect);
for (vector<string>::iterator it = vect.begin(); it != vect.end(); ++it)
{
cout << *it << endl;
}
return 0;
}
I wrote this code to test if the function vectorremove works, unfortunately it seems that vectorremove has no impact on the vector. Have I made any mistake in the use of remove in the definition of vectorremove?
The first problem in your code is that you are passing the vector by value and not by reference to vectorremove. You need to change that to
void vectorremove(vector<string>& v);
Then inside your vectorremove function you have another problems. vector::erase can invalidate all iterators, so you should onle remove inside the loop and do the erase after the loop.
void vectorremove(vector<string>& v)
{
vector<string>::iterator end{ v.end() };
for (vector<string>::iterator it = v.begin(); it != end; ++it)
{
end = remove(it + 1, end, *it);
}
v.erase(end, v.end());
}
First you are passing std::vector by value, not by reference. Therefore, any changes you make in vectorremove function won't be visible in main.
Furthermore, std::vector::erase might invalidate iterators so you must not use it inside the loop.
Your code could look like:
void vectorremove(std::vector<std::string>& v) {
auto end{ v.end() };
for (auto it = v.begin(); it != end; ++it)
{
end = std::remove(it + 1, end, *it);
}
v.erase(end, v.end());
}
Note the usage of auto instead of std::vector<std::string>::iterator.
However, STL provides handy functions to achieve what you want. One of them is std::unique which
Eliminates all but the first element from every consecutive group of
equivalent elements from the range [first, last) and returns a
past-the-end iterator for the new logical end of the range.
In order to remove duplicates from the std::vector, you can do something like:
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> v{ 1, 2, 3, 1, 2, 3, 3, 4, 5, 4, 5, 6, 7 };
std::sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
for (auto const i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
Remember that std::unique works as expected only on sorted std::vectors.
You only modify the copy of vector , you have to pass by reference to modify the actual
vector, why you don't use auto instead of std::vector::iterator. and you have to
know that erase invalidates all iterators pointing to the erased element and
beyond the erased element, keep the iterator valid by using erase's return value, also use std::getline inside the loop to store the value from std::cin to include the new line.
Alternatively your can use std::unique removes the duplicate value and works as expected after sorting the elements. and std::unique returns a past the end iterator for the new logical end of the range:-
#include <vector>
#include <algorithm>
#include <string>
std::vector<std::string> removeDuplicate(std::vector<std::string> & v){
std::vector<std::string> vec;
std::sort(std::begin(v), std::end(v));
auto pos = std::unique(std::begin(v), std::end(v));
vec.assign(std::begin(v), pos);
return vec;
}
int main(){
std::vector<std::string> vect{"John", "John", "Paul", "John", "Lucy", "Bob", "Bob"};
auto pureVector = removeDuplicate(vect);
for(auto const & v : pureVector){
std::cout << v << '\n';
}
}
I have a std::vector as described below:
std::vector<std::pair<int, const char*>> matrix;
This vector has the following values (for e.g.): values (as an example)
These values can be access here as follows:
matrix[0] = [0,Hello] // pseudo code (only showing values inside)
matrix[1] = [0,Fox] // pseudo code (only showing values inside)
matrix[2] = [1,Red] // pseudo code (only showing values inside)
I am iterating through the contents of the vector read the values, by doing this:
for (std::vector<std::pair<int, const char*>>::iterator it = matrix.begin(); it != matrix.end(); ++it)
{
std::pair<int, const char*> v_temp = *it;
std::cout << v_temp.first;
std::cout << v_temp.second;
}
Now, what this is doing is iterating from the first element of vector to the end element of the vector. What I want to do, is iterate only on the first elements (i.e. int values). So, from the tabular image I have attached, this current code will loop for [ row x column ] [ 9 x 2] = 18 times. What I want it for it to iterate only 9 times [ rows ] and not consider columns at-all.
How can I do that?
There are a lot of ways to skin this particular cat. One would be to use std::transform:
std::transform(v.begin(), v.end(),
std::ostream_iterator<int>(std::cout, "\t"),
[](auto const &p) { return p.first; });
TL;DR boost::transform_iterator is your friend.
Example taken from What is the equivalent of boost::make_transform_iterator in the standard library?:
// I couldn't realize how to specialize type of std::get, so I need this helper.
inline int tuple_fst(const std::tuple<int, const char*> &x) {
return x.first;
}
...
auto beg = boost::make_transform_iterator(matrix.begin(), tuple_fst);
auto end = boost::make_transform_iterator(matrix.end(), tuple_fst);
for (auto it = beg; it != end; ++it) {
std::cout << *it;
}
This is actually a nice question, I don't understand why it is so downvoted. You wanted something like rust's std::iter::Map or Haskell's map. Unfortunately, in C++ things get a bit more ugly if you want high level iterator functions.
Your loop iterates over the rows of the matrix. Element iof matrix is the "row" at index i (in this case a std::pair<int, const char*>. So if you have pushed back 9 pairs then the loop will iterate 9 times.
FYI: You can simplify your code using the C++ feature auto:
for(auto it = matrix.begin(); it != matrix.end(); ++it){
auto v_temp = *it;
std::cout << v_temp.first;
std::cout << v_temp.second;
}
A further simplification is
for(const auto& v_temp : matrix)
{
std::cout << v_temp.first;
// ...
}
You can use the C++11 for-range based loop for any object on which the compiler can call begin() and end() on.
I want to remove some elements from a vector and am using remove_if algorithm to do this. But I want to keep track of the removed elements so that I can perform some operation on them later. I tried this with the following code:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
struct IsEven
{
bool operator()(int n)
{
if(n % 2 == 0)
{
evens.push_back(n);
return true;
}
return false;
}
vector<int> evens;
};
int main(int argc, char **argv)
{
vector<int> v;
for(int i = 0; i < 10; ++i)
{
v.push_back(i);
}
IsEven f;
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(), f);
for(vector<int>::iterator it = f.evens.begin(); it != f.evens.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
return 0;
}
But this doesn't work as remove_if accepts the copy of my functor object, so the the stored evens vector is not accessible. What is the correct way of achieving this?
P.S. : The example, with even and odds is just for example sake, my real code is somethinf different. So don't suggest a way to identify even or odds differently.
The solution is not remove_if, but it's cousin partial_sort partition. The difference is that remove_if only guarantees that [begin, middle) contains the matching elements, but partition also guarantees that [middle, end) contains the elements which didn't match the predicate.
So, your example becomes just (note that evens is no longer needed):
vector<int>::iterator newEnd = partition(v.begin(), v.end(), f);
for(vector<int>::iterator it = newEnd; it != v.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
Your best bet is std::partition() which will rearrange all elts in the sequence such as all elts for which your predicate return true will precede those for which it returns false.
Exemple:
vector<int>::iterator bound = partition (v.begin(), v.end(), IsEven);
std::cout << "Even numbers:" << std::endl;
for (vector<int>::iterator it = v.begin(); it != bound; ++it)
std::cout << *it << " ";
std::cout << "Odd numbers:" << std::endl;
for (vector<int>::iterator it = bound; it != v.end(); ++it)
std::cout << *it << " ";
You can avoid copying your functor (i.e. pass by value) if you pass ist by reference like this:
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(),
boost::bind<int>(boost::ref(f), _1));
If you can't use boost, the same is possible with std::ref. I tested the code above and it works as expected.
An additional level of indirection. Declare the vector locally, and
have IsEven contain a copy to it. It's also possible for IsEven to
own the vector, provided that it is dynamically allocated and managed by
a shared_ptr. In practice, I've generally found the local variable
plus pointer solution more convenient. Something like:
class IsEven
{
std::vector<int>* myEliminated;
public:
IsEven( std::vector<int>* eliminated = NULL )
: myEliminated( eliminated )
{
}
bool
operator()( int n ) const
{
bool results = n % 2 == 0;
if ( results && myEliminated != NULL ) {
myEliminated->push_back( n );
}
return results;
}
}
Note that this also allows the operator()() function to be const. I
think this is formally required (although I'm not sure).
The problem that I see with the code is that the evens vector that you create inside the struct gets created everytime the remove_if algorithm calls it. So no matter if you pass in a functor to remove_if it will create a new vector each time. So once the last element is removed and when the function call ends and comes out of the function the f.evens will always fetch an empty vector. This could be sorted in two ways,
Replace the struct with a class and declare evens as static (if that is what you wanted)
Or you could make evens global. I wouldn't personally recommend that( it makes the code bad, say no to globals unless you really need them).
Edit:
As suggested by nabulke you could also std::ref something likke this, std::ref(f). This prevents you from making the vector global and avoids for unnecessary statics.
A sample of making it global is as follows,
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
vector<int> evens;
struct IsEven
{
bool operator()(int n)
{
if(n % 2 == 0)
{
evens.push_back(n);
return true;
}
return false;
}
};
int main(int argc, char **argv)
{
vector<int> v;
for(int i = 0; i < 10; ++i)
{
v.push_back(i);
}
IsEven f;
vector<int>::iterator newEnd = remove_if(v.begin(), v.end(), f);
for(vector<int>::iterator it = evens.begin(); it != evens.end(); ++it)
{
cout<<*it<<"\n";
}
v.erase(newEnd, v.end());
return 0;
}
This code seems to work just fine for me. Let me know if this is not what you wanted.
You may have another solution; only if you don't need to remove elts in the same time (do you?). With std::for_each() which returns a copy of your functor. Exemple:
IsEven result = std::for_each(v.begin(), v.end(), IsEven());
// Display the even numbers.
std::copy(result.evens.begin(), result.evens.end(), std::ostream_iterator<int> (cout, "\n"));
Take note that it is always better to create unnamed variables in c++ when possible. Here that solution does not exactly answer your primary issue (removing elts from the source container), but it reminds everyone that std::for_each() returns a copy of your functor. :-)