Search code examples
c++loopsiteratorunordered-mapunordered-set

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:

  1. If A and B are compared, I don't need to compare B and A.
  2. 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.


Solution

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