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]);
}
}
Related
vector<int> cutTheSticks(vector<int> arr) {
vector<int> res;
vector<int>::iterator it;
int i=0, mini=0, c=arr.size();
while(c>0) {
res.push_back(c);
mini=*min_element(arr.begin(),arr.end());
for(i=0;i<arr.size();i++) {
arr[i]-=mini;
}
for(auto it=arr.begin();it!=arr.end();it++) {
i=*it;
if(i==0)
arr.erase(it);
}
c=arr.size();
}
return res;
}
I am running this piece of code in the hackerank portal and not on any system.
The way you are using erase is causing the problem in this case. In fact, you exactly don't need a complex approach like this for the problem.
You can simply sort the array in reverse order and then use pop_back() while last element is 0. It will also help to reduce complexity as then you won't need to call min_element each time. You can directly use arr.back() for the minimum element.
Logic behind my approach:
In each iteration, you are subtracting minimum element from each element. This makes number(s) having the minimum value as 0. Clearly, since the array is sorted in reverse order, these numbers will be in the end of the array. You then want to remove these elements for which pop_back is one of the best available options.
Here is sample code:
vector<int> cutTheSticks(vector<int> arr) {
vector<int> res;
sort(arr.begin(), arr.end(), greater<int>());
while (not arr.empty()) {
res.push_back(arr.size());
for (auto &&i : arr)
i -= arr.back();
while (not (arr.back() or arr.empty()))
arr.pop_back();
}
return res;
}
PS:
If you want to stick with your original algorithm then replace
for (auto it = arr.begin(); it!=arr.end(); it++) {
i = *it;
if(i == 0)
arr.erase(it);
}
with something like:
arr.erase(remove(arr.begin(), arr.end(), 0), arr.end()); // called as erase-remove idiom
or
for (auto it = arr.begin(); it!=arr.end(); /* it++ */) {
i = *it;
if(i == 0)
it = arr.erase(it);
else
++it;
}
This thread may help you: Remove elements of a vector inside the loop.
I am using a vector in a C++ program and I would like to find the next element inside the vector when looping through it, similar to how it would work with a linked list creating a next node. I am planning to use this loop to check the current element in a vector against the next element to see if they are the same.
for (auto i = v.begin(); i < v.end()-1; ++i) {
if (i[0] == i[1]) {
// do stuff
}
}
You can just use this loop:
for (size_t i = 0; i < v.size()-1; ++i) {
if (v[i] == v[i+1] { // if current element equals next element
... // do something
}
}
Simple
You can use std::next.
// Example copied from page linked to.
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v{ 3, 1, 4 };
auto it = v.begin();
auto nx = std::next(it, 2);
std::cout << *it << ' ' << *nx << '\n';
}
// Output:
// 3 4
In case you use the vector as a circular list (that is, you consider the first element as the "next" of the last element), you can use the modulo operator against the length of the vector.
For example:
int getNext(std::vector<int> vect, size_t i) {
return vect[ (i+1) % v.size() ];
}
This solution is useful if you need to select the next element in a "round robin" way, especially out of a loop.
My question is very similar to How to find an item in a std::vector? However, I want to go further, suppose the item I am searching for appears several times in the vector, and I want to obtain its positions in the vector as well. For example, the vector I have is [ 1 3 4 3 7], and the item I want to search is 3. Then the positions of the item is 1 and 3. Using the std::find function, I can only obtain its first position in the vector. Any ideas?
Just stick it in a while loop,
auto i = std::find(v.begin(), v.end(), n);
std::vector<std::size_t> result;
while(i != v.end())
{
result.push_back(std::distance(v.begin(), i));
i = std::find(i + 1, v.end(), n);
}
Use std::find successive times, and then put all the results together. Use as first of the range in which you find, the position that the previous std::find returned to you plus one.
You can use std::find multiple times:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int>::iterator it = vec.begin();
while (it != vec.end())
{
it = std::find(it, vec.end(), 3);
// do something with *it
if (it != vec.end())
it++;
}
Or you can simply use std::for_each:
std::vector<int> vec;
// fill the vector with numbers
std::for_each(vec.begin(), vec.end(), [&](int i)
{
if (i == 3)
{
// do something
}
});
If you are looking for the indexes/iterators for the items, you can simply use a custom loop:
std::vector<int> vec;
// fill the vector with numbers
std::vector<int> results;
for (std::size_t i = 0; i < vec.size(); ++i)
{
if (vec[i] == 3)
{
results.push_back(i);
}
}
results will then hold all of the indexes for elements matching your criteria (in this case, ==3).
I've std::vector<type> myVector
lets say content is:
el1, el2, el3, splitElement, el4,el5
I'm splitting splitElement into split1 and split2
I want to have vector:
split2, el4, el5, el1, el2, el3, split1
Split2 should be begining, split1 end. Other elements order should be like in example. Let's treat vector as chain. I want to insert two elements and shift chain to make split2 first element.
What is the elegant and effective way doing it using stl.
My fast code for now (it's very ugly solution):
std::vector<type> before;
std::vector<type> after;
bool afterBool = false;
for(std::vector<type>::iterator it = myVector.begin(); it != myVector.end(); it++)
{
if(*it == splitElement)
{
afterBool = true;
before.push_back(split1);
after.push_back(split2);
}
else if(afterBool)
after.push_back(*it);
else
before.push_back(*it);
}
myVector.clear();
for(std::vector<type>::iterator it = after.begin(); it != after.end(); it++)
myVector.push_back(*it);
for(std::vector<type>::iterator it = before.begin(); it != before.end(); it++)
myVector.push_back(*it);
I've added it only cause I don't wanted to leave topic without any code.
How to do it in nice way?
Example:
std::vector<int> myvector = {1, 2, 3, 0, 4, 5};
int splitElement = 0;
int split1 = -1;
int split2 = -2;
First you find your splitElement:
auto it = std::find(myvector.begin(), myvector.end(), splitElement);
Then you rotate the vector at the point you found splitElement, using std::rotate algorithm:
std::rotate(myvector.begin(), it, myvector.end());
// this yields { 0, 4, 5, 1, 2, 3 }
And finally just assign split2 to the beggining and push split1 to the back:
myvector[0] = split2;
myvector.push_back(split1);
The vector now looks like this: {-2, 4, 5, 1, 2, 3, -1}.
It sounds like you want to partition your vector. So you can use std::partition
To take your example with integers and -1 as the split element.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Splitter
{
int split;
Splitter(int sp):split(sp){}
bool operator()(int i)
{
return split < i;
}
};
int main () {
vector<int> myvector;
vector<int>::iterator it, bound;
// set some values:
for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
bound = partition (myvector.begin(), myvector.end(), Splitter(5));
myvector.insert(bound, -1);
cout << "odd members:";
for (it=myvector.begin(); it!=myvector.end(); ++it)
cout << " " << *it;
cout << endl;
return 0;
}
Since you havent mentioned about the sorting requirement and < operation on the type.
i guess you just want to split the element and make the first split as the last element in a vector and second split as the first element of the vector
I guess the better way to do this is to use a Data structure (Linked list)
store the elements of the vector in LL
traverse the list till the split element
make the second element as head and first element as the tail of LL
the original tail should be pointing its next to original tal.
aftere these above operation are done.just traverse the ll and store back in a vector.
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());