When to use dot and arrow operator in C++ pair? - c++

I have written the following code for a vector in C++ STL:
vector<pair< int,pair<int,int>> > v;
vector<pair< int,pair<int,int>> >::iterator it;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++)
v.push_back(make_pair(a[i]+a[j],pair<int,int>(i,j)));
for(it=v.begin();it!=v.end();it++)
cout<<(it->first)<<(it->second.first);
There is no problem with this code. It works. What I want to know is why we are using arrow operator to access vector pair and dot operator to access pair inside pair?
How can I know confidently when to use what. What is the logic here?
PS: a is some array with n elements.

In the following code sample, it is of type iterator as you declared up top.
for(it=v.begin();it!=v.end();it++)
cout << it->first << it->second.first;
vector::iterator is a class in which the arrow operator is overloaded to return a reference to an item in the vector you are looping over. That's just how iterators work.
If you want a more traditional 'dot' operator iteration, this would suffice:
for(size_t i = 0; i < v.size(); i++)
{
cout<<(v[i].first) << (v[i].second.first);
}
Or even better:
for (auto &item : v)
{
std::cout << item.first << item.second.first;
}
I have no idea what sc and fc are in your code. Maybe that's an alias for first and second ?

Related

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] << " ";
}

How to get the "last" element from an unordered_set?

My question is slightly different from this one.
There is an unordered_set with TWO elements. I'd like to operate the two elements ''simultaneously'' like this:
unordered_set<vector<bool>> st;
st.insert(vector<bool>(100,true));
st.insert(vector<bool>(100,false));
// vector<bool> temp_v(100,true);
// temp_v[3] = false;
// st.insert(move(temp_v));
if (st.size()!=2) return;
for (int i=0; i<100; i++)
cout << (st.begin()->at(i)) ^ (st.rbegin()->at(i)) << endl;
However, unordered_set has no member function rbegin(). I know I can use an iterator pointing to u_s::begin() and advance it by one. Is there any more "elegant" way to do that?
-------------------------------------Solution------------------------------------------
Inspired by #YSC, an elegant way to achieve the purpose is:
auto & e1 = *begin(st);
auto & e2 = *(++begin(st));
for (int i=0; i<100; i++) cout << e1[i] ^ e2[i] << endl;
which, might rely on #include <algorithm>, is almost the same as the two-iterator solution.
Well, if you know for sure it has exactly two elements, KISS:
struct not_vector { /*...*/ };
unordered_set<not_vector> st;
// ...
not_vector const& first = *begin(st);
not_vector const& last = *(++begin(st));
unordered_set iterators are ForwardIterator on which operator++ is defined and do what you expect. On the other hand, there is no way to go backward, only BidirectionalIterator can. This is why there is no unordered_set::rbegin().
Is there any more "elegant" way to do that?
Yes this more obvious way to achieve pretty match the same:
int values[] { 0, 3 };
int index = random_number_generated_by_compiler_version() % 2;
std::cout << values[index] << values[!index] << std::endl;

Split vector to unique and duplicates c++

My goal is to split a vector into two parts: with unique values and with duplicates.
For example I have sorted vector myVec=(1,1,3,4,4,7,7,8,9,9) which should be split into myVecDuplicates=(1,7,4,9) and myVecUnique=(1,4,7,9,3,8). So myVecDuplicates contains all values that have duplicates while myVecUnique contains all values but in a single embodiment.
The order does not matter. My idea was to use unique as it splits a vector into two parts. But I have a problem running my code.
vector<int> myVec(8)={1,1,3,4,4,7,8,9};
vector<int>::iterator firstDuplicate=unique(myVec.begin(),myVec.end());
vector<int> myVecDuplicate=myVec(firstDuplicate,myVec.end());\\here error accures that says ' no match for call to '(std::vector<int>) (std::vector<int>::iterator&, std::vector<int>::iterator)'
vector<int> myVecUnique=myVec(myVec.begin()+firstDuplicate-1,myVec.end());
After running this code I get an error that says (2nd line) 'no match for call to '(std::vector) (std::vector::iterator&, std::vector::iterator)'
Please help me to understand the source of error or maybe suggest some more elegant and fast way to solve my problem (without hash tables)!
Ahh..Too many edits in your question for anyone's liking. Just keep it simple by using map.
In C++, map comes really handy in storing the unique + sorted + respective_count values.
map<int, int> m;
for(auto &t : myVec){
m[t]++;
}
vector<int> myVecDuplicate, myVecUnique;
for(map<int, int>::iterator it = m.begin(); it != m.end(); it++){
if(it->second > 1) myVecDuplicate.push_back(it->first);
myVecUnique.push_back(it->first);
}
Edit:
maybe suggest some more elegant and fast way to solve my problem (without hash tables)!
Sort the vector
Traverse through the sorted vector,
and do
if (current_value == previous_value){
if(previous_value != previous_previous_value)
myVecDuplicate.push_back(current_value);
}
else{
myVecUnique.push_back(current_value);
}
To start, initialize previous_value = current_value - 1
and previous_previous_value as current_value - 2.
While this may be frowned upon (for not using standard algorithms and such), I would write some simple solution like this:
vector<int> myVec = {1,1,3,4,4,7,8,9};
unordered_set<int> duplicates;
unordered_set<int> unique;
for(int & v : myVec)
{
if(unique.count(v) > 0)
duplicates.insert(v);
else
unique.insert(v);
}
O(n) complexity solution:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> myVec = {1,1,3,4,4,7,7,8,9,9};
std::vector<int> myVecDuplicatec;
std::vector<int> myVecUnique;
for(int &x : myVec)
{
if(myVecUnique.size() == 0 || myVecUnique.back() != x)
myVecUnique.push_back(x);
else
myVecDuplicatec.push_back(x);
}
std::cout << "V = ";
for(int &x : myVec)
{
std::cout << x << ",";
}
std::cout << std::endl << "U = ";
for(int &x : myVecUnique)
{
std::cout << x << ",";
}
std::cout << std::endl << "D = ";
for(int &x : myVecDuplicatec)
{
std::cout << x << ",";
}
}
cpp.sh/4i45x
std::vector has a constructor that accepts 2 iterators for range [first,second[ You cannot call constructor for existing object - it is already created, so your code
myVec(firstDuplicate,myVec.end());
actually tries to use myVec as a functor, but std::vector does not have operator() hence the error.
you have 2 ways, pass 2 iterators to constructor directly:
vector<int> myVecDuplicate(firstDuplicate,myVec.end());
or use copy initialization with temporary vector:
vector<int> myVecDuplicate = vector<int>(firstDuplicate,myVec.end());
Same for the second vector:
vector<int> myVecUnique(myVec.begin(),firstDuplicate);
as pointed by Logman std::unique does not seem to guarantee value of duplicates, so working solution can use std::set instead (and you would not have to presort source vector):
std::set<int> iset;
vector<int> myVecUnique, myVecDuplicate;
for( auto val : myVec )
( iset.insert( val ).second ? myVecUnique : myVecDuplicate ).push_back( val );

for loop with different types c++

I have a for loop which i need to loop over different kinds of arrays, the first one is map<string,vector<string>> and the second is an integer array.
to implement this i did :
struct {map<string,vector<string>>::iterator it; int i; } s;
int k = 0;
for ( s.it = m.begin(), s.i = 0; s.it != m.end(), s.i < size; s.i+=2)
{
while (k != integer_array[s.i] && k < size)
{
s.it++;
k++;
}
if (k == integer_array[s.i])
{
cout << s.it.first << endl; // this line does not complie
k = 0;
s.it = m.begin();
}
}
explain of what i'm trying to do:
integer_array stores indexes and i'm trying to print the map value at index which stored in integer_array.
any suggestions?
I guess your problem is in the iterator.
Instead of:
cout << s.it.first << endl;
Try:
cout << s.it->first << endl;
The reason is that a STL iterator behaves like a pointer: if you want to access the value pointed, then you must dereference your iterator (either through operator * or through operator ->).
In the current case, the pointed value is a std::pair of std::string and std::vector, and you want to print the first std::string. Thus, you need to write it->first.

accessing a specific point of a vector with an iterator

I am trying to figure out the best way of accessing a position in a vector using an iterator. I'm aware iterators behave like pointers, so this is the only method I came up with. I would like to know if there's a better or just a different way. Here's the code:
//This is a pointer to a vector of the class Particle BTW. vector < Particle > *particleList;
vector<Particle>::iterator it = particleList->begin();
// I assign a specific position outside the loop to a new iterator that won't be affected
vector<Particle>::iterator it2 = particleList->begin() + 3;
for( it; it != particleList->end(); it++){
it->draw();
//I'm interested in the velocity of this element in particular
cout << it2->vel << endl;
}
Thanks,
M
Try the following
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
std::cout << (i+3)->vel << "\n";
}
Note, there is no reason to use std::endl, std::endl has an implicit flush which lowers performance when outputting to say a log file, and when outputting to console it is already line buffered meaning that a line ending will already flush.
Note 2, you can only use + with i since i is a random access iterator because particleList is a std::vector, if you change say particleList to a std::list then the iterator will be a bidirectional iterator instead of a random access iterator and you will not be able to use + in that case you would need to use std::advance like WhozCraig mentioned, but do so on a copy like so:
for (auto i = particleList->begin(); i < particleList->begin(); ++i) {
i->draw();
auto i2 = i;
std::advance(i2, 3)
std::cout << i2->vel << "\n";
}
Though personally, in this case I would just iterate with two iterators instead of std::advance since std::advance is linear in time. Do something like:
auto i = particleList->begin();
auto i2 = particleList->begin();
std::advance(i2, 3);
for (; i < particleList->end(); ++i, ++i2) {
i->draw();
std::cout << i2->vel << "\n";
}
Note 3: (i+3) and i2 will run off the end of your list (vector), so do something smart there.