looping through a vector of iterators with an iterator - c++

I get an error in the final for loop:
error: conversion from '__normal_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >*,vector<__gnu_cxx::__normal_iterator<int*, std::vector<int> >>>' to non-scalar type '__normal_iterator<const int*,vector<int>>' requested
20 | for(vector<int>::const_iterator t=ind.begin(); t != ind.end(); ++t){
| ~~~~~~~~~^~
I kept looking for solutions to similar problems and I still don't get what I did wrong.
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,m,a;
vector<int>::iterator b;
cin>>n>>m;
vector<int> seq(n);
vector<vector<int>::iterator> ind;
for(int i=0;i<n;i++){
cin>>seq[i];
}
for(int i=0;i<m;i++){
cin>>a;
b=find(seq.begin(),seq.end(),a);
if(b!=seq.end()){
ind.push_back(b);
}
}
sort(ind.begin(),ind.end());
for(vector<int>::const_iterator t=ind.begin(); t != ind.end(); ++t){
cout<<*t;
}
return 0;
}

vector<int>::const_iterator is an iterator for a vector of int. An iterator for a vector of iterators is vector<vector<int>::iterator>::const_iterator.
To avoid typing such monster types, use auto:
for(auto t=ind.begin(); t != ind.end(); ++t){
cout<<*t;
}
or when you iterate from begin till end, a range based loop:
for(auto t : ind){
cout<<t;
}
As you didnt include the error (at the time of writing this) I fixed only the obvious error. I suppose you need to dereference the iterator to print the actual element (ie add a * in both examples above).

The vector ind is a vector of elements of the type std::vector<int>::iterator.
So in the for loop you have to write at least like
vector<vector<int>::iterator>::const_iterator t=ind.begin();
And it seems within the loop you mean
cout<<**t;
instead of
cout<<*t;

Related

How can I find repeated words in a vector of strings in C++?

I have a std::vector<string> where each element is a word. I want to print the vector without repeated words!
I searched a lot on the web and I found lots of material, but I can't and I don't want to use hash maps, iterators and "advanced" (to me) stuff. I can only use plain string comparison == as I am still a beginner.
So, let my_vec a std::vector<std::string> initialized from std input. My idea was to read all the vector and erase any repeated word once I found it:
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
}
}
}
I tried to test for std::vector<std::string> my_vec{"hey","how","are","you","fine","and","you","fine"}
and indeed I found
hey how are you fine and
so it seems to be right, but for instance if I write the simple vector std::vector<std::string> my_vec{"hello","hello","hello","hello","hello"}
I obtain
hello hello
The problem is that at every call to erase the dimension gets smaller and so I lose information. How can I do that?
Minimalist approach to your existing code. The auto-increment of j is what is ultimately breaking your algorithm. Don't do that. Instead, only increment it when you do NOT remove an element.
I.e.
for (int i = 0; i < my_vec.size(); ++i) {
for (int j = i + 1; j < my_vec.size(); ) { // NOTE: no ++j
if (my_vec[i] == my_vec[j]) {
my_vec.erase(my_vec.begin() + j);
}
else ++j; // NOTE: moved to else-clause
}
}
That is literally it.
You can store the element element index to erase and then eliminate it at the end.
Or repeat the cycle until no erase are performed.
First code Example:
std::vector<int> index_to_erase();
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
index_to_erase.push_back(j);
}
}
}
//starting the cycle from the last element to the vector of index, in this
//way the vector of element remains equal for the first n elements
for (int i = index_to_erase.size()-1; i >= 0; i--){
my_vec.erase(my_vec.begin()+index_to_erase[i]); //remove the component from the vector
}
Second code Example:
bool Erase = true;
while(Erase){
Erase = false;
for(int i=0;i<my_vec.size();++i){
for (int j=i+1;j<my_vec.size();++j){
if(my_vec[i]==my_vec[j]){
my_vec.erase(my_vec.begin()+j); //remove the component from the vector
Erase = true;
}
}
}
}
Why don't you use std::unique?
You can use it as easy as:
std::vector<std::string> v{ "hello", "hello", "hello", "hello", "hello" };
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
N.B. Elements need to be sorted because std::unique works only for consecutive duplicates.
In case you don't want to change the content of the std::vector, but only have stable output, I recommend other answers.
Erasing elements from a container inside a loop is a little tricky, because after erasing element at index i the next element (in the next iteration) is not at index i+1 but at index i.
Read about the erase-remove-idiom for the idomatic way to erase elements. However, if you just want to print on the screen there is a much simpler way to fix your code:
for(int i=0; i<my_vec.size(); ++i){
bool unique = true;
for (int j=0; j<i; ++j){
if(my_vec[i]==my_vec[j]) {
unique = false;
break;
}
if (unique) std::cout << my_vec[i];
}
}
Instead of checking for elements after the current one you should compare to elements before. Otherwise "bar x bar y bar" will result in "x x bar" when I suppose it should be "bar x y".
Last but not least, consider that using the traditional loops with indices is the complicated way, while using iterators or a range-based loop is much simpler. Don't be afraid of new stuff, on the long run it will be easier to use.
You can simply use the combination of sort and unique as follows.
#include <iostream>
#include <algorithm>
#include <vector>
int main() {
std::vector<std::string> vec{"hey","how","are","you","fine","and","you","fine"};
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end() ), vec.end());
for (int i = 0; i < vec.size(); i ++) {
std::cout << vec[i] << " ";
}
std::cout << "\n";
return 0;
}

any clear explanation of this?

I'm trying to learn C++ vectors.. Here is the code:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector <int> vec;
for(int i=0; i<=10; i++){
vec.push_back(i);
}
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
}
Can anybody tell me what this part is?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
I've searched the Internet but couldn't find a clear explanation.
Ok, it prints the numbers that we put it in the vector, but can I get a more technical explanation?
for(auto i=vec.begin(); i!=vec.end();i++){
cout<<*i<<" ";
}
This is just the iterators in C++.
begin() function is used to return an iterator pointing to the first element of the vector.
Similarly, end() function is used to return an iterator pointing past the last element of the vector.
auto just deduces the type of the variable i. You could have also specified it as std::vector<int>::iterator i = vec.begin() . That's the type of the iterator you are using to loop over the vector.
In the above piece of code, you are basically iterating from the beginning of the vector until the end of the vector.
Inside the loop, you are just dereferencing the iterator and printing the value at the current position where the iterator is.
What the above piece of code is doing is basically the same as the following type of loop, which uses indexing to loop over the array:
for(size_t i = 0; i != vec.size() ; i++){
cout << vec[i] << " ";
}
You should read more about iterators, as they are a core concept in C++. You can read more about them here:
iterators
std::vector.begin()
std::vector.end()
This is an iterator to the first element in the vector: vec.begin()
An iterator to one-past the last element of the vector: vec.end()
auto deduces the type of i from vec.begin(), its an iterator. We really do not need to care about the exact type.
We only need to know that we can increment it: i++.
And compare two iterators with each other to check if we are at the end: i != vec.end().
And we can derference iterators to get the element the "point to": *i.
Without iterators the loop could be written as:
for (size_t i=0; i<vec.size(); ++i) {
std::cout << vec[i];
}
That part simply prints all the elements of the vector. auto automatically determines what data structure it is given the parameters that define it. In this case, it is being used as a vector<int>::iterator. Mostly, this is used in other data structures, such as a map or a set, since those don't support random access. In a vector, you can simply do
for(int i = 0; i < vec.size(); i++)
{
cout << vec[i] << " ";
}

Can we store a value of a set in a variable? Like we can store a value of an array in a variable

I have tried to store a value of a set into a variable. I try this:
int a[1000],c[1000],ara[10000],t,n,i,j;
cin>>n;
set<int>st;
for(i=0; i<n; i++)
{
cin>>a[i];
st.insert(a[i]);
}
int p = st.size();
int m;
for(i=0;i<p;i++)
m = st[i];
error: no match for 'operator[]' (operand types are 'std::set<int>' and 'int')
std::set does not have an operator[], like an array does. You are trying to iterate through the values stored in the set. You do that using iterators, eg:
int n, j;
cin >> n;
set<int> st;
for(int i = 0; i < n; ++i)
{
cin >> j;
st.insert(j);
}
for(set<int>::iterator iter = st.begin(); iter != st.end(); ++iter)
{
int m = *iter;
// use m as needed...
}
/* simpler:
for(int m : st)
{
// use m as needed...
}
*/
A std::set does not support the concept of accessing elements via an index or key. It behaves more like a mathmatical set. That's why it does not overload operator[] and you can't access it's elements like that of an array, vector or map.
You can, however, iterate through the elements of a std::set using iterators:
for(auto it = st.begin(), end = st.end(); it != end; ++it) {
m = *it;
}
Or let the compiler do all the nasty stuff with a range-based for:
for(int item : st) {
m = item;
}
When you encounter such compiler errors, indicating you are using wrong a stl container, algorithm, ..., you can easily look it up at cppreference.com. Here is an example for set. You will see that there is no operator[] for std::set, hence the compiler error. Also, in your first for looop, you use st1 instead of st.
You seem to want to iterate over the std::set. You can do this in several ways, one is:
std::set<int> mySet;
/* ... */
for (const auto& element : mySet)
{ /* ... */ }
Note though that in your second loop, you'll just store the biggest int of the std::set in the variable m.
You probably confused a std::set with a std::map, which does have an operator[].

Vector Iterator not dereferencable (trying to manually reverse vector)

I'm trying to create a function which takes in a vector and simply reverses (manually). I'm aware of the existence of reverse(), but I ran into the "Vector iterator not dereferencable" problem and for educational purposes, I'd like to know what it means. I tried researching this problem and someone (on this forum) said that vect.end() is not dereferencable by definition, but from my understanding, using reverse_iterator is just reversing the ends, so following the logic; vect.rend should not be dereferencable.
vector<int> reverseVector(vector<int>);
int main()
{
vector<int> vec;
for (int i = 0; i < 11; i++)
{
vec.push_back(i);
}
vec = reverseVector(vec);
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++)
{
cout << *it << " ";
}
cout << endl;
return 0;
}
vector<int> reverseVector(vector<int> vect)
{
vector<int>::reverse_iterator ritr;
for (ritr = vect.rbegin(); ritr != vect.rend(); ritr++)
{
vect.insert(vect.begin(), *ritr);
vect.pop_back();
}
return vect;
}
You are deleting elements from the vector (popping from the back), which invalidates the reverse iterator.
You could just iterate through half of the vector and swap the elements, lke this:
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
vector<int> reverseVector(vector<int> vect) {
const size_t origin_size = vect.size();
for(size_t i = 0; i < origin_size/2; ++i)
swap(vect[i], vect[origin_size - 1 - i]);
return vect;
}
Your problem has nothing to do with the dereferencability or otherwise of rend(). You're modifying the vector while iterating over it, which invalidates the iterator.
To answer your original question, a reverse_iterator isn't just "reversing the ends" compared to a forward iterator. rbegin() is end() - 1, and rend() is begin() - 1.
If you add an element to the vector, ritr may be invalidated thus the error
Vector iterator not dereferencable.
Thus its better using an index as your loop variable or better a copy(temp) vector for reverse task.
Both insert and pop_back member functions modify the vector and invalidate iterators.
A tip as design-issue: use always const-reference in a function, unless you really know what you are doing. So you will avoid stepping in traps like this. For example:
vector<int> reverseVector(const vector<int> &vect)
Now you wont have this problem, because you can not modify vect.

How can I build a std::vector<std::string> and then sort them?

I have a bunch of strings that I need to sort. I think a std::vector would be the easiest way to do this. However, I've never used vectors before and so would like some help.
I just need to sort them alphanumerically, nothing special. Indeed, the string::compare function would work.
After that, how can I iterate through them to verify that they're sorted?
Here's what I have so far:
std::sort(data.begin(), data.end(), std::string::compare);
for(std::vector<std::string>::iterator i = data.begin(); i != data.end(); ++i)
{
printf("%s\n", i.c_str);
}
You can just do
std::sort(data.begin(), data.end());
And it will sort your strings. Then go through them checking whether they are in order
if(names.empty())
return true; // empty vector sorted correctly
for(std::vector<std::string>::iterator i=names.begin(), j=i+1;
j != names.end();
++i, ++j)
if(*i > *j)
return false;
return true; // sort verified
In particular, std::string::compare couldn't be used as a comparator, because it doesn't do what sort wants it to do: Return true if the first argument is less than the second, and return false otherwise. If you use sort like above, it will just use operator<, which will do exactly that (i.e std::string makes it return first.compare(second) < 0).
What is the question exactly? It seems everything is already there.
However, you should probably use std::cout << *i << std::endl;
i is an iterator == pointer to the data in the container, so * is needed
c_str() is a function of std::string and not a variable
The problems in your code do not relate to your question?
Some hints for you:
std::vector also overrides [] operator, so you can instead save the iterator hassle and use it like an array (iterate from 0 to vector.size()).
You could use std::set instead, which has automatically sorting on insertion (binary tree), so you save the extra sorting.
Using a functor makes your output even more fun: copy(V.begin(), V.end(), ostream_iterator<std::string>(cout, "\n"));
litb is correct, as always.
I just wanted to point out the more general point - anything that can be compared with < can be sorted with std::sort. I'll sometimes sneak an operator< member function into a struct, just so I can do this.
For sort use:
std::sort or std::vector< std::string>::sort(..) method.
To check if it is sorted:
use std::is_sorted for check is sorted - http://www.sgi.com/tech/stl/is_sorted.html
or
std::adjacent_find( v.begin(), v.end(), std::greater< std::string >() ) == v.end()
for your case you could use default comparator
EDITED:
std::is_sorted is not standard stl function, it defined in sgi stl implementation.
Thanks #Brian Neal for this note.
Sorting the string:
using namespace std; // to avoid using std everywhere
std::sort(data.begin(), data.end()); // this will sort the strings
Checking whether vector is sorted:
if(vec.empty())
return true; // empty vector is sorted correctly
for(std::vector< std::string>::iterator i=vec.begin(), j=i+1; j != vec.end(); ++i, ++j)
if(*i > *j) return false;
return true; // sort verified
C++11 Method to check sorted vector:
std::is_sorted(vec.begin(),vec.end())
Now printing the sorted vector:
for(std::vector< std::string>::iterator i = vec.begin(); i != vec.end(); ++i)
{
std::cout<< *i <<std::endl;
}
You could use a std::set, which is naturally a sorted container.
Try using comaprator:
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//comparing function only sorts if string size is equal and keeps the larger integgers at last.
bool myfunction (string i,string j)
{
int n=i.length();
int m=j.length();
if(n==m)
return (i<j);
return n<m;
}
int main() {
int n;
cin>>n;
vector <string> arr(n);
for(int i=0;i<n;i++)
cin>>arr[i];
sort(arr.begin(),arr.end(),myfunction);
for(int i=0;i<n;i++)
cout<<arr[i]<<endl;
return 0;
}