Easy way to iterate through multiple std::vectors in C++ - c++

I have two std::vectors of same type, and I need to iterate through both of them using the same routine. Something like this:
std::vector<int> values1, values2;
int counter = 0;
for (int val : values1) counter += val;
for (int val : values2) counter += val;
Is there any simple way to write the last two lines in a single loop, to avoid code repetition? Something that would look like this:
std::vector<int> values1, values2;
int counter = 0;
for (int val : values1, values2) counter += val;

If you don't need to access either vector after iterating over them, you could move them into a std::initializer_list and then iterate over that:
std::vector<int> values1{1, 2, 3};
std::vector<int> values2{4, 5, 6};
for (const auto& v : {std::move(values1), std::move(values2)}) {
for (auto value : v) {
std::cout << value << ' ';
}
}
// prints "1 2 3 4 5 6 "
As ShadowRanger pointed out below, moving from the original vectors isn't necessary if we instead iterate over an initializer list of std::reference_wrappers. This can be done by swapping std::move with std::cref (or std::ref if you need to mutate them):
for (const auto& v : {std::cref(values1), std::cref(values2)}) {
for (auto value : v.get()) {
std::cout << value << ' ';
}
}
// prints "1 2 3 4 5 6 ", as before

No, there isn't, sorry. At least not directly in the language.
Boost can do it:
for (int val : boost::range::join(values1, values2))
counter += val;
Because Boost can do it, you could make something to do it as well, by making an iterator type of your own that casts a "view" over both collections.
But, particularly in the simple case you've shown, it's often not worth it. If your loop body is more complex, I recommend hiving it off into a function that takes int. This can just be a lambda declared immediately above the loop. That's what I do.

With range-v3 you could write:
namespace rs = ranges;
namespace rv = ranges::views;
int counter = rs::accumulate(rv::concat(values1, values2), 0);
I suspect there will be library support for this by C++23 (or C++2b). All that is needed is a range adaptor views::concat, and the range-ification of the <numeric> header.

How about:
std::vector<int> values_vecs[2];
// ...
int counter = 0;
for (const auto& values : values_vecs)
for (int val : values) counter += val;
It's not exactly the same as your original code, however it can support easily more than 2 vectors.
In case the vectors are there already as two separate vectors, you can still go with:
std::vector<int> values1, values2;
//...
int counter = 0;
for (auto values_ptr : {&values1, &values2})
for (int val : *values_ptr) counter += val;

I used something like this to iterate through 3 different vectors of different size where one vector was dependent of the two other vectors (first_vector is dependent on the other vectors).
#include <iostream>
#include <vector>
int main() {
std::vector<int> first_vector{50, 20, 30, 5000};
std::vector<int> second_vector{10};
std::vector<int> third_vector{500, 10};
for (int i = 0, j = 0, k = 0; i < first_vector.size(); ++i, ++j, ++k) {
if (j == second_vector.size()) {
j = 0;
}
if (k == third_vector.size()) {
k = 0;
}
std::cout << first_vector[i] << '|' << second_vector[j] << '|'
<< third_vector[k] << '\n';
std::cin.get();
}
return 0;
}

Related

C++ is there another way to access members first and second than using a range for loop for std::vector <std::pair <int, int>>?

I solved another problem the other day involving a std::vector <std::pair<int,int>> called name.
My question is, how do I access the name.first and name.second of this type?
I ended up using a ranged-for loop, that solved my issue
for(i : name) { i->first , i->second}
But, is there another way? I am particularly interested in how to access this in a normal for loop, e.g
for(int i = 0; i < name.size(); i++) { std::vector::std::pair::name.first}
Can anybody shed some light on this for me?
In C++17, you can use a structured binding
for (auto & [a, b] : name) {
// a is a reference to the first of each pair
// b is a reference to the second of each pair
}
The usual way
for (size_t i = 0; i < name.size(); i++)
{
cout << name[i].first;
cout << name[i].second;
}
This is just the typical way to access a vector (or array) of structs.
BTW the code you said worked in fact does not, for(i : name) { i->first , i->second} should be for(i : name) { i.first , i.second}. Your version would work for a vector of pair pointers, but not for a vector of pairs.
If you are using C++17 (or greater) Structure Bindings can do this
#include <vector>
#include <utility>
int main()
{
std::vector <std::pair<int,int>> vp;
for (auto & [first,second] : vp)
{
// do something with first and second
};
}
See https://en.cppreference.com/w/cpp/language/structured_binding
As of C++17, you can use structured bindings:
#include <iostream>
#include <vector>
#include <tuple>
int main() {
std::vector<std::pair<int,int>> v{};
v.push_back({1, 11});
v.push_back({2, 22});
for (auto [a, b] : v) {
std::cout << a << " " << b << "\n";
} // 1 11
// 2 22
}
Note that auto in the structured binding declaration means each pair is taken by value (which is reasonable when working with fundamental types).
If you want to either read a non-fundamental type, or write via structured binding identifier, you may use auto const& or auto&, respectively. E.g.:
// add 'first' to 'second;
for (auto& [a, b] : v) {
b += a;
} // 1 11
// 2 22
// read only (by value)
for (auto [a, b] : v) {
std::cout << a << " " << b << "\n";
} // 1 12
// 2 24
There's also structured bindings:
#include <iostream>
#include <vector>
#include <utility>
int main()
{
std::vector<std::pair<int, int>> somePairs{ {1, 2}, {5, 10}, {12, 60} };
for (auto [first, second] : somePairs)
{
std::cout << "First = " << first << ", second = " << second << '\n';
}
return 0;
}
This automatically unpacks the std::pairs inside the std::vector into the first and second variables.
Output:
First = 1, second = 2
First = 5, second = 10
First = 12, second = 60
This is a very basic question about C++ syntax. I recommend a book instead of Stack Overflow.
The elegant way to do this is:
std::vector<std::pair<int, int>> names;
for(int i = 0; i < names.size(); i++) {
auto &name = names[i];
// now access name.first, name.second
}
unordered_map<int , int> mp;
for(auto x:mp)
{
cout<<x.first;
cout<<x.second;
}
This is the way you can access members first and second in a standard template library (STL) by creating a container with key-value and a mapped value with unique pair.

Need to iterate over entire object except for first two elements. Is there a design pattern?

I have a std::vector that I would like to iterate over each object except the first two. A foreach loop would be perfect if I didn't want two . i.e. for(const auto i : items)
Possible solutions I've thought of are erasing the first two and re-adding at the end
const auto firstEle = myVec[0];
const auto secEle = myVec[1];
myVec.erase(myVec.begin());
myVec.erase(myVec.begin());
for(const auto i : items)
{
//do stuff with i
}
myVec.insert(myVec.begin(), secEle);
myVec.insert(myVec.begin(), firstEle);
or have some sort of flag
unsigned int i = 0;
for(const auto j : items)
{
if(i < 2)
{
i++;
continue;
}
//do stuff with j
}
or use a while loop
unsigned int i = 2;
while(i < myVec.size())
{
const auto j = myVec[i];
//do stuff with j
i++;
}
All these seem more complicated than they need to be. Any better solutions that are simpler?
I usually go with a conventional loop for these things:
// verify myVec.size() > 2
for(auto it = myVec.begin()+2; it != myVec.end(); ++it) {
// work
}
If you want C++11 lambda magic, then
std::for_each(v.begin()+2, v.end(), [](auto& element) {
// do stuff
});
will do it.
In C++20, you can use std::views::drop. Taken directly from the example at cppreference.com:
#include <ranges>
#include <vector>
#include <iostream>
int main()
{
std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (int i : nums | std::views::drop(2))
{
std::cout << i << ' ';
}
std::cout << '\n';
return 0;
}
Output:
3 4 5 6 7 8 9
The easiest way to approach this kind of problems is to simply fall back to an indexed loop:
for(int i = 2; i < myVec.size(); i++) {
//do stuff with `myVec[i]`
}
For std::vector<>, this is just as efficient as the iterator based loop, and the loop control says exactly what it does on the lid. Most importantly, because you are comparing integers for < instead of iterators for !=, you do not run any risk to trigger undefined behavior when the vector is too short.

initializing a vector with a lambda being fed the index in c++

Is there a library function for initializing a vector based on the index of its elements ?
This would shorten things like :
#include <vector>
using namespace std;
int main() {
auto square = [] (int n) {return n*n;};
vector<int> v(5, 0);
for (int i = 0; i < 5; i++){
v[i] = square(i);
}
}
The way that comes to mind is to break it into two steps. In this case std::iota will fill the vector with the inputs (0, 1, 2, etc). Then std::transform will perform your function square on each of the elements and replace them in the vector.
int main()
{
auto square = [] (int n) {return n*n;};
std::vector<int> v(5, 0);
std::iota(v.begin(), v.end(), 0);
std::transform(v.begin(), v.end(), v.begin(), square);
for (int i : v)
std::cout << i << ' ';
}
Output
0 1 4 9 16
Honestly this is the kind of thing that will be much more concise and streamlined once ranges are available, C++20 working example
int main()
{
auto square = [] (int n) {return n*n;};
for (int i : std::views::iota(0, 5) | std::views::transform(square))
std::cout << i << ' ';
}
For a vector there is easy way to calculate its index by subtracing pointers:
std::for_each(v.begin(),v.end(),
[&v,&square](auto& elem){ elem = square(&elem - &v[0]);});
by auto& elem you access original item of vector then index is calculated by &elem - &v[0] which is passed into square.

c++ array any two terms are equal

In an array, how do I check if any two variables are equal in something like
total_milk[7] = { b_milk, e_milk, d_milk, g_milk, a_milk, m_milk, h_milk };
without using casework
Iterate over the elements in the array, adding each element to an unordered_set.
The return value from unordered_set::insert() will tell you whether the element already was in the set.
Use two for loops and compare each element with other elements:
bool anyTwo(total_milk a[], std::size_t n) {
for (std::size_t i = 0; i < n - 1; i++) {
for (std::size_t j = i + 1; j < n; j++) {
if (a[i] == a[j]) {
return true;
}
}
}
return false;
}
This assumes your overloaded the == operator in your class. The second for loop counter j starts from i + 1 instead of 0 or i as there is no need to compare the already compared values or compare the element with itself.
The naive approach, which is fine for small data sets, is to simply use a comparison loop where each element is compared with every other element following it - there's no point comparing with those at or before an element since either the comparison has already been done or you will be comparing an item with itself.
The following complete program illustrates this approach:
#include <iostream>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
for (size_t one = 0; one < sizeof(milk) / sizeof(*milk) - 1; ++one) {
for (size_t two = first + 1; two < sizeof(milk) / sizeof(*milk); ++two) {
if (milk[one] == milk[two]) {
std::cout << "Duplicate item: " << milk[one] << '\n';
return 1;
}
}
}
std::cout << "No duplicates\n";
}
For larger data sets, you can turn to the more optimised collections provided by the C++ library, such as the sets. A set is able to hold one of each value and has the useful property that it will return the fact that you tried to insert a duplicate, by returning both an iterator to the inserted/original item and a boolean value indicating whether it was new or a duplicate.
Like the earlier program, this one shows how you can use this method:
#include <iostream>
#include <unordered_set>
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
std::unordered_set<int> checkSet;
for (auto val: milk) {
auto iterAndBool = checkSet.insert(val);
if (! iterAndBool.second) {
std::cout << "Duplicate item: " << val << '\n';
return 1;
}
}
std::cout << "No duplicates\n";
}
A substantial improvement could be made to that using templates. This would allow it to handle arrays of any data type (assuming it has equality operators, of course) without have to code up specialisations for each. The code for that would be along the following lines:
#include <iostream>
#include <unordered_set>
template<class T> T *CheckDupes(T *collection, size_t count) {
std::unordered_set<T> checkSet;
for (size_t idx = 0; idx < count; ++idx) {
auto iterAndBool = checkSet.insert(collection[idx]);
if (! iterAndBool.second) {
return &(collection[idx]);
}
}
return nullptr;
}
int milk[] = { 3, 1, 4, 1, 5, 9 };
int main() {
int *dupe;
if ((dupe = CheckDupes<int>(milk, sizeof(milk) / sizeof(*milk))) != nullptr) {
std::cout << "Duplicate item: " << *dupe << '\n';
return 1;
}
std::cout << "No duplicates\n";
}
The templated function above will either return nullptr (if there are no duplicates) or the address of one of the duplicates. It's a simple matter to check that return value and act appropriately.
I suspect further improvement could be made to handle other collection types (not just naked arrays) but I'll leave that as an exercise for when you've mastered simpler templates :-)

how can I find repeated elements in a vector [duplicate]

This question already has answers here:
Checking for duplicates in a vector [duplicate]
(5 answers)
Closed 9 years ago.
I have a vector of int which can include maximum 4 elements and minimum 2, for example :
std::vector<int> vectorDATA(X); // x means unknown here
What I want to do is to erase the elements that are repeated for example :
vectorDATA{1,2,2} to vectorDATA{1,2}
vectorDATA{1,2,3} to nothing changes
vectorDATA{2,2,2} to vectorDATA{2}
vectorDATA{3,2,1,3} to vectorDATA{3,2,1}
vectorDATA{1,2,1,2} to vector{1,2}
and so on
here a code simple :
cv::HoughLines(canny,lineQ,1,CV_PI/180,200);
std::cout << " line Size "<<lineQ.size()<< std::endl;
std::vector<int> linesData(lineQ.size());
std::vector<int> ::iterator it;
if(lineQ.size() <=4 && lineQ.size() !=0 ){
if(lineQ.size()==1){
break;
}else {
for ( int i = 0; i<lineQ.size();i++){
linesData[i] = lineQ[i][1]; // my comparison parameter is the lineQ[i][1]
}
// based on the answer I got I'm trying this but I really don't how to continue ?
std::sort(lineQ.begin(),lineQ.end(),[](const cv::Vec2f &a,const cv::Vec2f &b)
{
return ????
}
I tried use a for and do while loop, but I didn't get it, and the function std::adjacent_find this has a condition that the elements should be consecutive.
Maybe it's easy but I just don't get it !
thanks for any help !
The easy way is sort then unique-erase, but this changes order.
The c++11 order preserving way is to create an unordered_set<int> s; and do:
unordered_set<int> s;
vec.erase(
std::remove_if( vec.begin(),vec.end(), // remove from vector
[&](int x)->bool{
return !std::get<1>(s.insert(x)); // true iff the item was already in the set
}
),
vec.end() // erase from the end of kept elements to the end of the `vec`
);
which is the remove-erase idiom using the unordered_set to detect duplicates.
I didn't see a sort-less source code in the already mentioned answers, so here it goes. Hash table for checking duplicates, shifting unique elements towards the front of the vector, note that src is always >= dst and dst is the number of copied, i.e. unique elements at the end.
#include <unordered_set>
#include <vector>
#include <iostream>
void
uniq (std::vector<int> &a) {
std::unordered_set<int> s;
size_t dst = 0;
for (size_t src = 0; src < a.size(); ++src) {
if (s.count (a[src]) == 0) {
s.insert (a[src]);
a[dst++] = a[src];
}
}
a.resize (dst);
}
int
main () {
std::vector<int> a = { 3, 2, 1, 3, 2, 1, 2, 3, 4, 5 ,2, 3, 1, 1 };
uniq (a);
for (auto v : a)
std::cout<< v << " ";
std::cout << std::endl;
}
If you want to realy remove repeated elements, you may try something like this:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
int data[] = {1,2,3,2,1};
vector<int> vectorDATA = (&data[0], &data[0] + 5);
sort(vectorDATA.begin(),vectorDATA.end());
for(int i = 0; i < vectorDATA.size()-1; ++i)
{
if(vectorDATA[i] == vectorDATA[i+1])
vectorDATA.erase(vectorDATA.begin()+i+1);
}
for(int i = 0; i < vectorDATA.size();++i)
{
cout << vectorDATA[i] << " ";
}
cout << endl;
return 0;
}
Lack of of this method is then elements lost his order.