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

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

Related

Prevent adding multiple same items to vector in recursion

I got a method that adds adjacent Voxels to a vector. This method uses an vector with all the remaining points (means, they still need to be looked at as they are possible adjacents) and looks on every one of them if it is near enough to be added. If an element is a neighbor it also checks all adjacents of this element to add them too. This happens in a recursive manner.
void remove(std::vector<pcl::PointXYZ> &vec, pcl::PointXYZ p) {
for (int i = 0; i < vec.size(); i++) {
if (vec[i].x == p.x && vec[i].y == p.y && vec[i].z == p.z) {
vec.erase(vec.begin() + i);
break; // as all points should be unique
}
}
}
void addAdjacents(pcl::PointXYZ start, std::vector<pcl::PointXYZ> &newCluster, std::vector<pcl::PointXYZ> &remainingPoints) {
for (pcl::PointXYZ p : remainingPoints) {
if (distance(p, start) < 0.015) {
newCluster.push_back(p);
remove(remainingPoints, p);
if (remainingPoints.size() > 0)
addAdjacents(p, newCluster, remainingPoints);
}
}
}
The problem is, that many points from the remainingPoints-vector are added to the newCluster multiple times. I thought this wouldn't happen but it seems like internally it makes copies of the vector in the recursion? If a point is removed in a deeper layer the for-loop in the outer execution is somehow still iterating over this (removed) element.
I am fairly new to c++ so I am not sure how to prevent this. Can anyone help me? Thanks!
For sure I can just write a method addToCluster which just checks if the vector has this element before adding it but I thought that maybe there is a more elegant way to prevent this happening in the first place.
Edit:
As I understand I am breaking my iterator in the loop. So I would need to somehow update my iterator after calling addAdjacents. Is this right? Can I do something like that?
You need to separate identifying the points you wish to migrate with erasing them from the input.
template<typename BidirIt>
BidirIt addAdjacentsImpl(pcl::PointXYZ start, std::vector<pcl::PointXYZ> &newCluster, BidirIt first, BidirIt last) {
auto part = std::stable_partition(first, last, [&](auto p){ return distance(p, start) >= 0.015; });
for (auto it = part; it != last; ++it) {
newCluster.push_back(*it);
part = addAdjacentsImpl(*it, newCluster, first, part);
}
return part;
}
This only re-orders the elements, such that those we wish to remove are after those we wish to keep. I've written it as a template because I don't care to name the particular iterator types.
void addAdjacents(pcl::PointXYZ start, std::vector<pcl::PointXYZ> &newCluster, std::vector<pcl::PointXYZ> &remainingPoints) {
auto last = addAdjacentsImpl(start, newCluster, remainingPoints.begin(), remainingPoints.end());
remainingPoints.erase(last, remainingPoints.end());
}
Here
list.erase(list.begin() + i);
You erase an element from the std::vector called list (really not the best name for a vector) which invalidates iterators at and after the erased position. It isnt that obvious, but this erasing happens while addAdjacents iteratates over the same container. Leaving only the broken part in we have
void addAdjacents(pcl::PointXYZ start, std::vector<pcl::PointXYZ> &newCluster, std::vector<pcl::PointXYZ> &remainingPoints) {
for (pcl::PointXYZ p : remainingPoints) {
newCluster.push_back(p);
//remove(remainingPoints, p); // <- calls erase
remainingPoints.erase( remainingPoints.begin() + some_index);
}
}
}
Erasing an element from remainingPoints does break the range-based loop, because under the hood it uses iterators that potentially got invalidated in remove.

How can I code a loop that compares every element of an unordered_set with all the others, using iterators in C++?

I have an unordered_set and I need to pick each element and compare it with all the others.
Notes:
If A and B are compared, I don't need to compare B and A.
My unordered_set is the value of an unordered_map, for which the key is a pair.
I tried the following:
unordered_map <pair<int, int>, unordered_set <int>, boost::hash<std::pair<int,int>>> gridMap;
unordered_map <int, rigidBody*> objectsMap;
auto gridMapIt = gridMap.begin();
while (gridMapIt != gridMap.end()) // loop the whole gridMap
{
auto setItOut = gridMapIt->second.begin();
while (setItOut != gridMapIt->second.end()) // loop each element of the set
{
auto setItIn = gridMapIt->second.begin();
while (setItIn != gridMapIt->second.end()) // versus each other element
{
//compare and do stuff
++setItIn;
}
checked.insert({ objectsMap[*setItOut]->getID(), objectsMap[*setItIn]->getID() });
checked.insert({ objectsMap[*setItIn]->getID(), objectsMap[*setItOut]->getID() });
++setItOut;
}
++gridMapIt;
}
The error I am getting is "Expression: cannot dereference end list iterator". If I remove or comment the innermost while loop, it works fine.
Thanks in advance.
The use of *setItIn after the loop is invalid. At that point you have an iterator that points past the last element. That's what the error is telling you.
If you change from while to for you can use the scoping rules to stop yourself from dereferencing invalid iterators.
Rather than populate checked, you can start the inner loop from the next element, rather than the first.
for (auto & gridElem : gridMap) {
for (auto setItOut = gridElem.second.begin(), setEnd = gridElem.second.end(); setItOut != setEnd; ++setItOut) {
for (auto setItIn = std::next(setItOut); setItIn != setEnd; ++setItIn) {
//compare and do stuff
}
// setItIn not visible here
}
}

How to get int position of vector loop

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).

Iterating through a C++ vector with wrap-around

I have an assignment to iterate through a vector and erase every third number. If it hits the end of the vector, it should continue counting again from the first entry, until only one number remains. The user inputs how many numbers should be in the vector.
I'm having trouble getting used to the difference between vectors and arrays - just last week we had a problem that involved wrapping around an array, which was solved with mod, but I quickly figured out this wouldn't work for vectors.
Here was my idea so far: Iterate through and delete every third entry until the size of the vector is 1.
while (vector.size > 1) {
for(std::vector<int>::iterator i = suitors.begin(); i <= suitors.end(); i++) {
// here, add a case for if it hits the end, start over
if (i = suitors.end()) {
i = suitors.begin();
}
suitors.erase(suitors.at(i) + 2);
}
The problem I'm having is figuring out how to have it start over, as spits out an error when I try to use i in this way.
Any advice or tips to get me on the right path here? I'm beginning to see how versatile vectors are, but they just aren't clicking yet. I'm also not sure if there is a better way to stop it from iterating besides the while loop.
I'd use remove_if to move items in the vector to the end whenever an index variable that is incremented each time reaches 3.
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v{1,2,3,4,5,6};
unsigned index = 0; // this is the index variable used to remove elements
auto end = v.end(); // point to the current end of the vector
// keep looping until there is only 1 element in the vector
while(std::distance(v.begin(), end) > 1) {
// remove_if will call the predicate for each element
// the predicate simply increments the index each time, and when it reaches
// 3 indicates that element should be removed
// remove_if will move items to the end of the vector and return an
// iterator to the end of the new range, so we'll update the end variable
// with the result
end = std::remove_if(v.begin(), end, [&index](int) {
if(++index == 3) {
// reset the index and indicate this element should be removed
return (index = 0), true;
}
return false;
});
for(auto iter = v.begin(); iter != end; ++iter) {
std::cout << *iter << ' ';
}
std::cout << '\n';
}
// erase all the elements we've removed so far
v.erase(end, v.end());
}
Output:
1 2 4 5
1 2 5
1 5
1
Live demo
The outer while loop I'm assuming means to go as long as the vector has more than one element, but this should be included in the for, not another loop
The syntactic issue is in the if:
if (i = suitors.end())
// ^ should be ==
otherwise you're just assigning end to your iterator
for(std::vector<int>::iterator i = suitors.begin(); suitors.size() > 1; ++i) {
// ^ loop condition changed
if (i == suitors.end()) {
i = suitors.begin();
}
suitors.erase(suitors.at(i) + 2);
}
modifying a container as you iterate through it is dangerous though..

I want to write a function that iterates through a list?

I want to write a function that iterates through a list, but takes two elements if they equal a target.
The logic could be to have two loops; first iterate through list and see if any element + the first = target, then second, then third
etc..
int i;
int max = list.size;
for(i=0; i<=max; i++)
{
if()
}
in c++
int i;
int max = resistors.size();
int curr;
for(curr = 0; curr<=resistors.size(); curr++)
{
for(i=1; i<=max; i++)
{
if((resistors[curr]+resistors[i])==target){
ComposeSerial(resistors[curr], resistors[i]);
}
}
}
i believe one thing is missing to make sure that it goes through again?
It might help if you thought about it slightly differently. You said "first iterate through list and see if any element + the first = target". What if you phrased it as "Iterate through the list and see if the current element + any other element in the list = target". All I've done is consolidated your placement of "the first, then second, then third etc..." into the "current element".
Your original phrasing suggests only one loop, with some magic to get the first element, then the second, etc. This reversed phrasing suggests two loops: one to get each element, then an inner loop to test the current element with every other element in the list. Hopefully that way of thinking will clear up any confusion.
Edit:
Since this didn't clear up all the confusion, I'm going to add some pseudocode:
for all items in list
for all items in list
if element from outer loop and element from inner loop meet your condition
return some value
One obvious optimization would be for the inner loop to start after the element from the outer loop, like so:
for all items in list
for all items in list after the element from the outer loop
...
Depending on the problem, you may want to include the outer element at the start of the inner loop:
for all items in list
for all items in list starting at the element from the outer loop
To write the actual code, grab your textbook, or the nearest C++ reference, or go to cplusplus.com, look up the documentation for the specific container type you're using, and determine the best way to iterate through your elements from there.
Edit 2 - Response to Edited Question
Thanks for the updated question. The only issues I see here are, as #leetNightshade pointed out in the comment, the inner loop should start at curr + 1 (or curr, if you want to allow the test for an element with itself, which you probably don't), and your loops should terminate when curr < resistors.size(), and i < max, respectively. Otherwise, you will include one element past the end of your list in your loop, which will have nasty consequences.
Okay, this question was a confusing/weird one, but I've got something that's still a work in progress for you. It's a bit weird, but bear with me.
template<typename V>
V Add(const V v1, const V v2)
{
return v1 + v2;
}
template<class T,typename V>
bool FindTwoEqualTarget(const T& list, const V target, V& elem1, V& elem2, V (*Process)(const V v1, const V v2) = Add)
{
for(T::const_iterator iter = list.begin(); iter != list.end(); )
{
T::const_iterator iter2 = iter;
iter = iter2++;
for( ; iter2 != list.end(); ++iter2)
{
if(target == Process((*iter),(*iter2)))
{
elem1 = (*iter);
elem2 = (*iter2);
return true;
}
}
}
return false;
}
You can use it like this:
list<int> iList = list<int>();
iList.push_back(5);
iList.push_back(6);
iList.push_back(1);
iList.push_back(4);
iList.push_back(3);
iList.push_back(9);
int val1;
int val2;
FindTwoEqualTarget(iList, 11, val1, val2);
I know you want the function to return a list, I'm playing around with some things now to easily set this up for you, but you can work off of this for now I think.