How to iterate through a vector of vector in C++? - c++

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
}
}

Related

memory out of range Vector [duplicate]

This question already has answers here:
Removing item from vector while iterating?
(8 answers)
Closed 2 years ago.
I'm writing this program why it throws an error in toupper('a')?
void test2(void) {
string n;
vector<string> v;
auto it = v.begin();
do {
cout << "Enter a name of a fruit: ";
cin >> n;
v.push_back(n);
} while (n != "Quit");
v.erase(v.end() - 1);
sort(v.begin(), v.end(), [](string g, string l) { return g < l; });
dis(v);
for (auto i : v) {
if (i.at(0) == toupper('a')) {
cout << i << endl;
v.erase(remove(v.begin(), v.end(), i));
}
}
dis(v);
}
Can someone help me to find the error?
Since you already tried to implement the erase-remove-idiom, that's how it can be used in this case:
v.erase(std::remove_if(v.begin(), v.end(), [](const std::string &item) {
return std::toupper(item.at(0)) == 'A';
}), v.end());
Here I assumed, that i.at(0) == toupper('a') is a typo and should be toupper(i.at(0)) == 'A'.
Write your deletion loop like this:
for ( auto it = std::begin( v ); it != std::end( v ); )
{
if ( toupper( it->at( 0 ) ) == 'A' )
it = v.erase( it );
else
++it;
}
If you do it the way you're doing it you'll invalidate the iterator and then never reassign it a valid iterator which is needed to correctly loop through the vector.
The problem here :
for (auto i : v) {
if (i.at(0) == toupper('a')) {
cout << i << endl;
v.erase(remove(v.begin(), v.end(), i));
}
}
is that you are modifying the vector inside the loop with erase() which invalidates the iterators used internally to implement the for range loop.
The loop is a syntactic sugar for something like this :
{
auto&& range = v;
auto&& first = std::begin(v); // obtained once before entering the loop
auto&& last = std::end(v); // obtained once before entering the loop
for (; first != last; ++first)
{
auto i = *first; // first will be invalid the next time after you call erase()
if (i.at(0) == toupper('a')) {
cout << i << endl;
v.erase(remove(v.begin(), v.end(), i)); // you are invalidating the iterators and then dereferencing `first` iterator at the beginning of the next cycle of the loop
}
}
}
Why calling erase() invalidates the vector ?
This is because a vector is like a dynamic array which stores its capacity (whole array size) and size (current elements count), and iterators are like pointers which point to elements in this array
So when erase() is called it will rearrange the array and decrease its size, so updating the end iterator and your first iterator will not be pointing to the next item in the array as you intended . This illustrates the problem :
std::string* arr = new std::string[4];
std::string* first = arr;
std::string* last = arr + 3;
void erase(std::string* it)
{
std::destroy_at(it);
}
for (; first != last; ++first)
{
if (some_condition)
erase(first); // the last element in the array now is invalid
// thus the array length is now considered 3 not 4
// and the last iterator should now be arr + 2
// so you will be dereferencing a destoryed element since you didn't update your last iterator
}
What to learn from this ?
Never do something which invalidates the iterators inside for range loop.
Solution:
Update iterators at each cycle so you always have the correct bounds :
auto&& range = v;
auto&& first = std::begin(v); // obtained once before entering the loop
auto&& last = std::end(v); // obtained once before entering the loop
for (; first != last;)
{
auto i = *first;
if (i.at(0) == toupper('a'))
{
first = v.erase(remove(v.begin(), v.end(), i));
last = std::end(v);
}
else
{
++first;
}
}

Removing duplicate elements in using the function "remove"

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';
}
}

loop hangs for iterated std::erase on std::list

I'm trying to remove duplicate combinations of integer vectors stored in a list using a hash table. Iterating over each integer vector in the list, I:
Calculate the hash_value (thash)
See if the hash value is already in the hash table (pids)
If it's in the hash table, erase that vector from the list.
Otherwise, add that value to the hash_table and increment the list
iterator
Print statements seem to confirm my logic, but the loop hangs at the fourth step of iteration. I've commented the it++ and vz.remove(it) that cause the problem and only show the logic in the code below. The code is also available through ideone: https://ideone.com/JLGA0f
#include<iostream>
#include<vector>
#include<list>
#include<cmath>
#include<unordered_set>
using namespace std;
double hash_cz(std::vector<int> &cz, std::vector<double> &lprimes) {
double pid = 0;
for(auto it = cz.begin(); it != cz.end(); it++) {
pid += lprimes[*it];
}
return pid;
}
int main(){
// create list of vectors
std::list<std::vector<int>> vz;
vz.push_back({2,1});
vz.push_back({1,2});
vz.push_back({1,3});
vz.push_back({1,2,3});
vz.push_back({2, 1});
// vector of log of prime numbers
std::vector<double> lprimes {2, 3, 5, 7};
for (auto it = lprimes.begin(); it != lprimes.end(); it++) {
*it = std::log(*it);
}
std::unordered_set<double> pids;
double thash;
for (auto it = vz.begin(); it != vz.end(); ) {
thash = hash_cz(*it, lprimes);
std::cout << thash << std::endl;
// delete element if its already been seen
if (pids.find(thash) != pids.end()) {
std::cout << "already present. should remove from list" << std::endl;
// vz.erase(it);
}
else {
// otherwise add it to hash_table and increment pointer
std::cout << "not present. add to hash. keep in list." << std::endl;
pids.insert(thash);
// it++;
}
it++;
}
for (auto it = vz.begin(); it != vz.end(); it++) {
for (auto j = it -> begin(); j != it -> end(); j++) {
std::cout << *j << ' ';
}
std::cout << std::endl;
}
return 0;
}
Problem is this line of code:
vz.erase(it);
It keeps iterator where it was ie leaves it invalid. It should be either:
vz.erase(it++);
or
it = vz.erase( it );
Note: std::unoredered_set::insert() return value tells you if insert was succesfull or not (if the same value element is there already), you should call it and check result. In your code you do lookup twice:
if (pids.insert(thash).second ) {
// new element added
++it;
} else {
// insertion failed, remove
it = vz.erase( it );
}
As std::list provides remove_if() your code can be simplified:
vz.remove_if( [&pids,&lprimes]( auto &v ) {
return !pids.insert( hash_cz(v, lprimes) ).second );
} );
instead of whole loop.
If the element has already been seen, you erase() the it node and then increment it at the end of the loop: undefined behaviour. Try erase(it++) instead.
If the element has not been seen, you increment it and then do it again at the end of for, yielding UB if it was end() - 1 as it moves past end.

How to get to the specified element of vector<list<int> >?

I have code like this:
vector<list<int> > a(b);
Inside vector I have few lists, something like this:
{2,1}, {2,2}, {4,5} etc.
How to get to the specified element from the list inside that vector?
Lists are not directly accessible, so you'll need to iterate over each list.
Example:
std::vector< std::list< int > > a;
a.push_back( {1,2,3} );
a.push_back( {4,5,6} );
a.push_back( {7,8,9} );
// You cannot do this, as list does not have direct access.
// std::cout << a[0][0];
// You must access each element via iterator for each list. This will print 1...9.
for( auto it = a[0].begin(); it!= a[0].end(); ++it ) std::cout << *it << std::endl;
for( auto it = a[1].begin(); it!= a[1].end(); ++it ) std::cout << *it << std::endl;
for( auto it = a[2].begin(); it!= a[2].end(); ++it ) std::cout << *it << std::endl;
To access an element from one of the lists, you need to first access the list containing the said element.
For example, to print every element greater than a certain variable (let's say 2) you could do something like this:
#include <vector>
#include <list>
#include <iostream>
int main (void) {
std::vector<std::list<int> > vecList;
int someVariable = 2;
for (int i = 1; i < 5; ++i) {
vecList.push_back(std::list<int> (i, i)); /* fill the vector with 4 lists {1}, {2, 2}, {3, 3, 3} {4, 4, 4, 4} */
}
/*this first loop will iterate over the content of the vector, not the content of the lists*/
for (const auto& ls : vecList) {
/*this will iterate over the content of each list in the vector*/
for (auto head = ls.begin(), tail = ls.end(); head != tail; ++head) {
if (*head > someVariable) { //*head is different from head
std::cout << *head << std::endl;
}
}
}
}
N.B: Read about std::vector, std::list and iterator.
You can do something like this:
std::vector<std::list<int> > arr;
for(const auto & i : arr) {
auto first = i.begin();
auto last = i.end();
while (first != last) {
std::cout << *first << std::endl;
++first;
}
}
First of all I iterate throughout arr. Then on each step I have get i element (it is std::list) and I create iterator on first element of this list. Then I read all elements from this list and print them out. It is very easy to understand

Remove an element from a vector by value - C++

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.