How to get int position of vector loop - c++

How to get int position of this loop? Thank you.
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (; a != vect.end() && b != vect2.end() && c != vect3.end(); a++, b++, c++) {
}
I need to print values of other variable, but I need to get actual unsigned int position of this vector loop.
I need to print double vector using this position of this vector.
And how to get the last index of vector.
My problem is for for loop with multiple vectors and getting index from it next to use only last of indexes.

As Angew shows, a simple indexed loop may be preferable when you need indices.
However, it is possible to get the index from an iterator as well:
auto a = vect.begin();
auto b = vect2.begin();
auto c = vect3.begin();
for (/*the loop conditions*/) {
auto index = a - vect.begin();
}
It is also possible to get the index of a forward iterator using std::distance, but it would be unwise to use it in a loop, since the complexity will be linear for non-random-access iterators.
In the case of forward iterators (and generic code that must support forward iterators), you can write a loop which has both the index variable, and the iterators.
P.S. it is potentially preferable to use pre-increment with iterators. Probably only matters in debug build.

It's simple: if you need indices, don't use iterators:
for (
size_t idx = 0, idxEnd = std::min({vect.size(), vect2.size(), vect3.size()});
idx < idxEnd;
++idx
)
{
auto& obj1 = vect[idx];
auto& obj2 = vect2[idx];
auto& obj3 = vect3[idx];
}
(The above code initialises idxEnd once at the start of the loop, so that it's not needlessly recomputed at each iteration. It's just an optimisation).

Related

C++ Simplify loop over map and extending/overwriting of vector

Given
std::vector<int> vec1 of size s_vec and capacity c.
std::vector<int> vec2.
std::map<int, int> m of size s_m >= s_vec.
std::unordered_set<int> flags.
bool flag = False
I want to copy as many values of m (in order) into vec1 (overwriting previous values) without exceeding the capacity c. If any values remain I want to push those values to the end of vec2. For each of these, values I want to check if they are in flags. If they are, I'd like to set flag to true.
This is how I currently, achieve this:
int i = 0;
for (auto const& e : m) {
if(i < c) {
if(i == vec1.size()) {
vec1.push_back(e.second);
} else {
vec1.at(i) = e.second;
}
} else {
vec2.push_back(e.second);
if(flags.count(e.second)){
flag = true;
}
}
}
I am new to C++ coming from python and R. Therefore, I assume that this can be simplified quite a bit (with iterators?). What can I do to improve the code here?
Your code must increment i at the end of each loop for it to work.
If you can use c++20 and its ranges, I would probably rewrite it completely, to something like:
using namespace std::views; // for simplicity here
std::ranges::copy(m | take(c) | values, vec1.begin());
std::ranges::copy(m | drop(c) | values, std::back_inserter(vec2));
flag = std::ranges::any_of(vec2, [&flags](int i){return flags.contains(i);});
The beauty of this, is that it matches your requirements much better.
The first lines does: "I want to copy as many values of m (in order) into vec1 (overwriting previous values) without exceeding the capacity c."
The second line does: "If any values remain I want to push those values to the end of vec2."
The third line does: "For each of these, values I want to check if they are in flags. If they are, I'd like to set flag to true."
Building on the comments of #PaulMcKenzie and the answers provided by #Nelfeal and #cptFracassa, this is what I ended up with.
size_t new_size = std::min(vec1.capacity(), m.size());
vec1.resize(new_size);
std::transform(m.begin(),
std::next(m.begin(), new_size),
vec1.begin(),
[](std::pair<int, int> p) { return p.second; });
std::transform(std::next(m.begin(), new_size),
m.end(),
std::back_inserter(vec2),
[&flags, &flag](std::pair<int, int> p) {
if(flags.count(p.second)) {
flag = true;
}
return p.second;
});
In the first part, instead of doing either push_back or assignment to at, you can just clear the vector and push_back everything. clear does not change the capacity.
Your loop is doing two different things, one after the other (and by the way, I assume you forgot to increment i). You should split it into two loops.
With all that, your code becomes:
vec1.clear();
auto it = m.begin();
for (int i = 0; i < c; ++i) {
vec1.push_back(it->second);
++it;
}
while (it != m.end()) {
vec2.push_back(it->second);
if(flags.count(it->second)){
flag = true;
}
++it;
}
At this point, you can also use standard algorithms (std::copy, std::transform as mentioned in the comments).

Using "std::set", take elements

In my code I used an array, I decided to try std :: set. I did this with an array:
for (int i=0; i<100; i++)
{
drawNMS(true, myMassive[myStr+i]);
}
myStr is added by buttons.
For std :: set, as I understand it, I need to use an iterator.
I try to do so:
std::set <int>::iterator iter;
for(iter=mySet.begin(); iter!=mySet.end();iter++)
{
drawNMS(true, myStr+*iter);
}
Where to insert for (int i = 0; i <100; i ++) correctly so that the end result is like when working with an array?
If you want to iterate over first 100 elements of a set, then do this:
std::set <int>::iterator iter;
int counter = 0;
for(iter=mySet.begin(); iter!=mySet.end() && counter < 100;++iter, ++counter)
{
drawNMS(true, myStr+*iter);
}
If you can use C++20, there is std::ranges which provides std::ranges::advance that works with a boundary, so your end-iterator can be found like this (not tested):
auto endSet100 = std::ranges::advance(mySet.begin(), 100, mySet.end());
This end-iterator can then be used like the original end-iterator. If you use std::advance, you have to do the boundary check yourself and the advance works on the iterator itself without returning a new iterator.
For simpler looping:
for (const auto& elem: std::ranges::subrange(mySet.begin(), std::ranges::advance(mySet.begin(), 100, mySet.end()))
{
drawNMS(true, myStr+elem);
}
It may be a bit longer, but it states: loop a subrange from the beginning to the 100th element or all if less elements are present.

Adding a new statement each iteration of a for loop. Queue with 2d arrray

I am trying to create a stream of numbers through a 2d array kind of like a queue but over 2 dimensions.
The final function will take std::string.
I have written some pretty horrific code.. eventually. I looked for a pattern but the thing that gets me is each time the number moves down the queue it needs another line of code and it has to move into the next element in the array.
I figure once I can do that I can put it in a loop.
so you basically add another line of code each time it adds a new number from the iterator.
intarray[0][0] = *it;
++it;
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][5] = intarray[0][4];
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
intarray[0][0] = *it;
++it;
intarray[0][6] = intarray[0][5];
intarray[0][5] = intarray[0][4];
intarray[0][4] = intarray[0][3];
intarray[0][3] = intarray[0][2];
intarray[0][2] = intarray[0][1];
intarray[0][1] = intarray[0][0];
the numbers go down each time a new number is added from the iterator
I think these nested loops is what you need
auto jj = 1u;
while (!condition)
{
intarray[0][0] = *it;
++it;
for (auto ii=jj; ii >= 1 ; --ii)
intarray[0][ii] = intarray[0][ii-1];
++jj;
}
where condition is whatever condition when you need to stop the process.This code is not very efficient, though.
EDIT
As I understand you need to use both dimensions, so you have options:
a) if you know the size of your data beforehand, and I think it is the case, since you use statically allocated intarray[N][M]:
for (auto kk=N-1; 0 <= kk; --kk)
for (auto ii=M-1; 0 <= ii ; --ii)
{
intarray[kk][ii] = *it;
++it;
}
you simply fill the array in reverse order, and there is no need to overwrite values many times.
b) if you don't know the size beforehand, but have enough memory (and time):
populate dynamically-sized container (I'd recommend std::vector<int>) with data and go route a)
c) if you don't know the size beforehand and don't have enough memory to hold temporary container, you are not able to use statically allocated array. The only solution I see is to populate an std::vector<T> with data, and then write a wrapper function to get the elements in right order.
EDIT2:
According to the image you posted in the commentary, you need simple wrapper around an array. Disclaimer: I have not tested the code below, nevertheless, it should work, maybe after minor tweaks.
//while you can do it without class, I prefer this way
class MyArray
{
public:
//push value in the array
void push_back(const int a)
{
//move values using std::memmove as suggested above
std::memmove(&(arr[1]),&(arr[0]),2*N - 1);
//store first element
arr[0]=a;
}
//calculate index in array and return
int at(const int a, const int b)
{
if (0 == a) //first row
return arr.at(b); //return just the index
if (1 == a) //second row
return arr.at(N - 1 - b); //if
}
private:
//dimension of the array
static const int N = 10;
//contiguous static array is enough here
//one can use C-style array, but no point for doing so
std::array<int, 2*N> arr;
}
//usage
MyArray mArr;
while(!condition)
{
mArr.push_back(*it);
std::cout<<mArr.at(1,2)<<std::endl;
}
To 'move the queue' it is handy to use std::memmove, as suggested by Some programmer dude. Since std::memmove operates over contiguous memory, use std::array, std::vector or 1D C-style array instead of 2D C-style array to hold all elements. To get values calculate the right index for it, depending on the row (first or second).

Start value for vector loop

Say I have the following:
int numFields = 0;
for ( auto & isFieldBlank : InputProcessor::numericFields_isBlank ) {
if ( !isFieldBlank ) {
numFields += 1;
}
}
InputProcessor::numericFields_isBlank is a bool vector of all numeric input values indicating whether the input values are empty true or populated false.
I have two related questions:
Is there a better way to count the populated fields in the vector?
Is there a way to provide a starting index to the for loop iterator?
A range based for loop will always run the entire range, you cant change that unless you adapt the range. What you can do though is use std::count/std::count_if to count the instances for you like
auto count = std::count(container.begin(), container.end(), true);
and to change the start and stop positions you can use std::next to move the iterator like
auto count = std::count(std::next(container.begin(), some_value),
std::next(container.end(), -some_other_value),
true);
Is there a better way to count the populated fields in the vector?
You can simplify the body of the for loop to:
numFields += (!isFieldBlank);
The complete for loop will be
for ( auto & isFieldBlank : InputProcessor::numericFields_isBlank ) {
numFields += (!isFieldBlank);
}
Is there a way to provide a starting index to the for loop iterator?
You certainly can. However, you will need to use a normal for loop, not a range-for loop.

Loop over all (unordered) pairs of elements in a vector

I have a std::vector of some data (Points in my case) and I want to loop over all distinct pairs of elements. The order of the pair is not important (as I am only interested in the distance of the points). With a classic for loop what I would want to do would be something like:
std::vector<double> vec{-1., 3., 5., -8., 123., ...};
for (std::vector<double>::size_type first = 0; first < vec.size(); ++first) {
for (std::vector<double>::size_type second = first+1; second < vec.size();
++second) {
// Compute something using std::fabs(vec.at(first)-vec.at(second))
}
}
My question is now if one can achieve this more elegantly using range based loops.
I wouldn't attempt to coerce it into a range based loop (since contriving the start of the inner loop will be tricky), but I would work directly with the iterators to clarify the loop body and to make the code less dependent on the specific container you're using:
for (auto first = vec.begin(); first != vec.end(); ++first){
for (auto second = first + 1; second != vec.end(); ++second){
// Your vec.at(first) is now simply *first.
}
}
Note that first + 1 is always valid since first is never vec.end() when first + 1 is evaluated.
std::vector::at is also required by the C++ standard to check that the supplied index is in the bounds of the vector (and throw a std::out_of_range exception if it isn't within the bounds), which is an unnecessary overhead in your case.
I provide this answer only because OP want a way of doing that with
range based for loops. It isn't more elegant than ordinary loops.
If your vector doesn't have duplicate numbers you can use reverse iteration instead of beginning from a specific point in the second loop, so that you can use range based for in your iterations.
for reverse iteration by range based for loops you want an adapter class.
template <typename It>
class reverse_adapter
{
public:
reverse_adapter(It rbegin, It rend)
: _rbegin(rbegin), _rend(rend)
{}
It begin() const { return _rbegin; }
It end() const { return _rend; }
private:
It _rbegin;
It _rend;
};
template<typename Container>
reverse_adapter<typename Container::reverse_iterator> make_reverse(Container& container)
{
reverse_adapter<typename Container::reverse_iterator> adapter(std::rbegin(container), std::rend(container));
return adapter;
}
And use this adapter for reverse iteration in second loop.
for(auto val : vec)
{
for (auto second_val : make_reverse(vec)) // Start from last to current item in first loop
{
if (val == second_val) break; // Instead of first + 1 in second loop
auto dif = val - second_val;
}
}