The goal is to access the "nth" element of a vector of strings instead of the [] operator or the "at" method. From what I understand, iterators can be used to navigate through containers, but I've never used iterators before, and what I'm reading is confusing.
If anyone could give me some information on how to achieve this, I would appreciate it. Thank you.
You need to make use of the begin and end method of the vector class, which return the iterator referring to the first and the last element respectively.
using namespace std;
vector<string> myvector; // a vector of stings.
// push some strings in the vector.
myvector.push_back("a");
myvector.push_back("b");
myvector.push_back("c");
myvector.push_back("d");
vector<string>::iterator it; // declare an iterator to a vector of strings
int n = 3; // nth element to be found.
int i = 0; // counter.
// now start at from the beginning
// and keep iterating over the element till you find
// nth element...or reach the end of vector.
for(it = myvector.begin(); it != myvector.end(); it++,i++ ) {
// found nth element..print and break.
if(i == n) {
cout<< *it << endl; // prints d.
break;
}
}
// other easier ways of doing the same.
// using operator[]
cout<<myvector[n]<<endl; // prints d.
// using the at method
cout << myvector.at(n) << endl; // prints d.
In C++-11 you can do:
std::vector<int> v = {0, 1, 2, 3, 4, 5};
for (auto i : v)
{
// access by value, the type of i is int
std::cout << i << ' ';
}
std::cout << '\n';
See here for variations: https://en.cppreference.com/w/cpp/language/range-for
Typically, iterators are used to access elements of a container in linear fashion; however, with "random access iterators", it is possible to access any element in the same fashion as operator[].
To access arbitrary elements in a vector vec, you can use the following:
vec.begin() // 1st
vec.begin()+1 // 2nd
// ...
vec.begin()+(i-1) // ith
// ...
vec.begin()+(vec.size()-1) // last
The following is an example of a typical access pattern (earlier versions of C++):
int sum = 0;
using Iter = std::vector<int>::const_iterator;
for (Iter it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
The advantage of using iterator is that you can apply the same pattern with other containers:
sum = 0;
for (Iter it = lst.begin(); it!=lst.end(); ++it) {
sum += *it;
}
For this reason, it is really easy to create template code that will work the same regardless of the container type.
Another advantage of iterators is that it doesn't assume the data is resident in memory; for example, one could create a forward iterator that can read data from an input stream, or that simply generates data on the fly (e.g. a range or random number generator).
Another option using std::for_each and lambdas:
sum = 0;
std::for_each(vec.begin(), vec.end(), [&sum](int i) { sum += i; });
Since C++11 you can use auto to avoid specifying a very long, complicated type name of the iterator as seen before (or even more complex):
sum = 0;
for (auto it = vec.begin(); it!=vec.end(); ++it) {
sum += *it;
}
And, in addition, there is a simpler for-each variant:
sum = 0;
for (auto value : vec) {
sum += value;
}
And finally there is also std::accumulate where you have to be careful whether you are adding integer or floating point numbers.
Vector's iterators are random access iterators which means they look and feel like plain pointers.
You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [].
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
int sixth = *(it + 5);
int third = *(2 + it);
int second = it[1];
Alternatively you can use the advance function which works with all kinds of iterators. (You'd have to consider whether you really want to perform "random access" with non-random-access iterators, since that might be an expensive thing to do.)
std::vector<int> vec(10);
std::vector<int>::iterator it = vec.begin();
std::advance(it, 5);
int sixth = *it;
Here is an example of accessing the ith index of a std::vector using an std::iterator within a loop which does not require incrementing two iterators.
std::vector<std::string> strs = {"sigma" "alpha", "beta", "rho", "nova"};
int nth = 2;
std::vector<std::string>::iterator it;
for(it = strs.begin(); it != strs.end(); it++) {
int ith = it - strs.begin();
if(ith == nth) {
printf("Iterator within a for-loop: strs[%d] = %s\n", ith, (*it).c_str());
}
}
Without a for-loop
it = strs.begin() + nth;
printf("Iterator without a for-loop: strs[%d] = %s\n", nth, (*it).c_str());
and using at method:
printf("Using at position: strs[%d] = %s\n", nth, strs.at(nth).c_str());
Related
I have a set of type set<int> and I want to get an iterator to someplace that is not the beginning.
I am doing the following:
set<int>::iterator it = myset.begin() + 5;
I am curious why this is not working and what is the correct way to get an iterator to where I want it.
myset.begin() + 5; only works for random access iterators, which the iterators from std::set are not.
For input iterators, there's the function std::advance:
set<int>::iterator it = myset.begin();
std::advance(it, 5); // now it is advanced by five
In C++11, there's also std::next which is similar but doesn't change its argument:
auto it = std::next(myset.begin(), 5);
std::next requires a forward iterator. But since std::set<int>::iterator is a bidirectional iterator, both advance and next will work.
The operator+ doesn’t define for this structure and only It make sense for random access iterators.
First solution:
You can use std::advance, the function uses repeatedly the increase or decrease operator (operator++ or operator--) until n elements have been advanced.
set<int>::iterator it = myset.begin();
std::advance(it, 5);
std::out << *it << std::endl; // == it + 5
Second solution:
Use std::next or std::prev functions,The performance same as the old one because uses repeatedly the increase or decrease operator (operator++ or operator--)until n element have been advanced.
Note: If it is a random access iterator, the function just uses just
once operator+ or operator-.
set<int>::iterator it1 = myset.begin();
std::next(it1, 5); // == it1 + 5
std::out << *it1 << std::endl; // == it1 + 5
set<int>::iterator it2 = myset.end();
std::prev(it2, 5); // == it2 - 5
std::out << *it2 << std::endl; // == it2 - 5
Note: If you want to access, vectors are very efficient accessing its elements (just like arrays) and relatively efficient adding or removing elements from its end.
Get element at index from C++11 std::set
std::set in C++ has no getter by index so you'll have to roll your own by iterating the list yourself and copying into an array then indexing that.
For example:
#include<iostream>
#include<set>
using namespace std;
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
int myarray[uniqueItems.size()]; //create an int array of same size as the
//set<int> to accomodate elements
int i = 0;
for (const int &num : uniqueItems){ //iterate over the set
myarray[i] = num; //assign it to the appropriate array
i++; //element and increment
}
cout << myarray[0] << endl; //get index at zero, prints 10
cout << myarray[1] << endl; //get index at one, prints 20
cout << myarray[2] << endl; //get index at two, prints 30
}
Or a handy dandy function to step through then return the right one:
int getSetAtIndex(set<int> myset, int index){
int i = 0;
for (const int &num : myset){ //iterate over the set
if (i++ == index){
return num;
}
}
string msg = "index " + to_string(index) + \
"is out of range";
cout << msg;
exit(8);
}
int main(){
set<int> uniqueItems; //instantiate a new empty set of integers
uniqueItems.insert(10);
uniqueItems.insert(20); //insert three values into the set
uniqueItems.insert(30);
cout << getSetAtIndex(uniqueItems, 1);
}
Take a vector of vector of int's how do I print all of them from begin to end
for(row=v.begin();row!=v.end();row++){
for(col=row->begin();col!=row->end();col++){
//cout<<?
}
}
What should be used in inner for loop to print each element
Personally, I like iterating over vectors just using a simple for loop from 0 to size(), but this is how you would do it with iterators:
for(vector< vector<int> >::iterator row = v.begin(); row != v.end(); ++row) {
for(vector<int>::iterator col = row->begin(); col != row->end(); ++col) {
cout << *col;
}
}
See: Iteration over std::vector: unsigned vs signed index variable
v.begin() returns an iterator to the beginning of the sequence
v.end() returns an iterator to the element past the end of the sequence
You can loop through your structure using those iterators:
for(auto it_row =v.begin(); it_row!=v.end(); it_row++){
for(auto it_col=it_row->begin();it_col!=it_row->end();it_col++){
cout<<*it_col<<endl;
}
}
In order to deference (get the value) your iterator you need to use the following syntax: *it_col
I used auto (C++ 11) instead of explicitly putting the iterator type:
vector<vector<int>>::const_iterator it_row = v.begin()
vector<int>::const_iterator it_col = it_row->begin()
You can find more details about iterators here.
If you are using c++11 then, you can use range based for loop;
for (const auto & items : v)
for (const auto & item : items)
cout << item;
Is there any STL function which does this?
For vector:
4 4 5 5 6 7
The expected output should be 2,because of one 6 and 7
Would you be kind to help me count them classic if there is no STL function?
I don't think there is an algorithm for that in STL. You can copy into a multimap or use a map of frequencies as suggested, but it does extra work that's not necessary because your array happens to be sorted. Here is a simple algorithm that counts the number of singular elements i.e. elements that appear only once in a sorted sequence.
int previous = v.front();
int current_count = 0;
int total_singular = 0;
for(auto n : v) {
if(previous == n) // check if same as last iteration
current_count++; // count the elements equal to current value
else {
if(current_count == 1) // count only those that have one copy for total
total_singular++;
previous = n;
current_count = 1; // reset counter, because current changed
}
}
if(current_count == 1) // check the last number
total_singular++;
You could also use count_if with a stateful lambda, but I don't think it'll make the algorithm any simpler.
If performance and memory doesn't matter to you, use std::map (or unordered version) for this task:
size_t count(const std::vector<int>& vec){
std::map<int,unsigned int> occurenceMap;
for (auto i : vec){
occurenceMap[i]++;
}
size_t count = 0U;
for (const auto& pair : occurenceMap){
if (pair.second == 1U){
count++;
}
}
return count;
}
with templates, it can be generalize to any container type and any containee type.
Use std::unique to count the unique entries(ct_u) and then user vector count on the original one (ct_o). Difference ct_o-ct_u would give the answer.
P.S.: this will only work if the identical entries are together in the original vector. If not, you may want to sort the vector first.
Using algorithm:
std::size_t count_unique(const std::vector<int>& v)
{
std::size_t count = 0;
for (auto it = v.begin(); it != v.end(); )
{
auto it2 = std::find_if(it + 1, v.end(), [&](int e) { return e != *it; });
count += (it2 - it == 1);
it = it2;
}
return count;
}
Demo
Is there a clean way to check if I am currently at the second to last element in an iteration in C++? As in:
for (vector::iterator it = v.begin(); it < v.end(); ++it)
{
if (it points to second to last element)
cout << "at second to last";
}
The easiest way would be to compare your iterator against one which does indeed point to the second-to-last. And an easy way to get that is:
vector::iterator secondLast = v.end() - 2;
Assuming of course that v.size() >= 2. But the above doesn't generalize to other container types, for which you could do this:
vector::iterator secondLast = (++v.rbegin()).base();
This should rewind from the last element one step, then convert to a regular (forward) iterator. This will work with other container types like lists.
Or perhaps clearer for the general solution:
vector::iterator secondLast = v.end();
std::advance(secondLast, -2);
Again this requires size of 2 and iterators of random access or bidirectional type.
And finally, a C++11 solution:
auto secondLast = std::prev(v.end(), 2);
Try something like this:
vector::iterator end = v.end(), stl;
bool has_stl = (v.size() >= 2);
if (has_stl) stl = end-2;
for (vector::iterator it = v.begin(); it < end; ++it)
{
if ((has_stl) && (it == stl))
cout << "at second to last";
}
You can do this with some containers:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); it++) {
if (vec.end() - it == 3) {
std::cout << *it << std::endl;
}
}
return 0;
}
A solution below:
auto pos = std::next(std::begin(v), std::distance(std::begin(v), std::end(v))-2);
for (auto it = std::begin(v); it != std::end(v); ++it)
{
if (it == pos)
cout << "at second to last: " << *pos;
}
pos is now an iterator pointing to the second to last position, and the functions std::next and std::distance use the best implementation possible (i.e. constant complexity for random iterators, linear complexity for bidirectional/forward iterators).
I am working on a problem where I have to create subvectors from a bigger vector. If the elements in the vector are consecutive I have to create a vector of those elements. If there are elements which are not consecutive then a vector of that single elements is created. My logic is as below
vector<int> vect;
for (int nCount=0; nCount < 3; nCount++)
vect.push_back(nCount);
vect.push_back(5);
vect.push_back(8);
vector<int>::iterator itEnd;
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
The functor NotConsecutiveis as below
return (int first != int second-1);
So I am expecting the std::adjacent_find will give me back the iterators such that I can create vector one{0,1,2,3}, vector two{5} and vector{8}. But I am not sure if there is any simpler way?
Edit:I forgot to mention that I have std::adjacent_find in a loop as
while(itBegin != vect.end())
{
itEnd = std::adjacent_find (vect.begin(), vect.end(), NotConsecutive());
vector<int> groupe;
if( std::distance(itBegin, itEnd) < 1)
{
groupe.assign(itBegin, itBegin+1);
}
else
{
groupe.assign(itBegin, itEnd);
}
if(boost::next(itEnd) != vect.end())
{
itBegin = ++itEnd;
}
else
{
vector<int> last_element.push_back(itEnd);
}
}
Does it make any sense?
I think this is what is being requested. It does not use adjacent_find() but manually iterates through the vector populating a vector<vector<int>> containing the extracted sub-vectors. It is pretty simple, IMO.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vect { 0, 1, 2, 3, 5, 8 };
// List of subvectors extracted from 'vect'.
// Initially populated with a single vector containing
// the first element from 'vect'.
//
std::vector<std::vector<int>> sub_vectors(1, std::vector<int>(1, vect[0]));
// Iterate over the elements of 'vect',
// skipping the first as it has already been processed.
//
std::for_each(vect.begin() + 1,
vect.end(),
[&](int i)
{
// It the current int is one more than previous
// append to current sub vector.
if (sub_vectors.back().back() == i - 1)
{
sub_vectors.back().push_back(i);
}
// Otherwise, create a new subvector contain
// a single element.
else
{
sub_vectors.push_back(std::vector<int>(1, i));
}
});
for (auto const& v: sub_vectors)
{
for (auto i: v) std::cout << i << ", ";
std::cout << std::endl;
}
}
Output:
0, 1, 2, 3,
5,
8,
See demo at http://ideone.com/ZM9ssk.
Due to the limitations of std::adjacent_find you can't use it quite the way you want to. However it can still be useful.
What you can do is to iterate over the collection, and use std::adjacent_find in a loop, with the last returned iterator (or your outer loop iterator for the first call) until it returns end. Then you will have a complete set of consecutive elements. Then continue the outer loop from where the last call to std::adjacent_find returned a non-end iterator.
Honestly, I don't find any clear disadvantage of using a simple hand-crafted loop instead of standard functions:
void split(const std::vector<int> &origin, vector<vector<int> > &result)
{
result.clear();
if(origin.empty()) return;
result.resize(1);
result[0].push_back(origin[0]);
for(size_t i = 1; i < origin.size(); ++i)
{
if(origin[i] != origin[i-1] + 1) result.push_back(vector<int>());
result.back().push_back(origin[i]);
}
}