# Using standard library to simplify pairwise iteration of container values

I came up with this code whilst answering this question.

Is there a simpler way of doing this using standard library?

I want to iterate over every object and do something with every other object.

For example, 4 values 1, 2, 3, 4 would pair like:

(1, 2), (1, 3), (1, 4)
(2, 3), (2, 4)
(3, 4)


Each value combines with every other value. None combine with themselves, and symmetric pairings are considered the same.

This might be useful in a collision system where you want to check every solid with every other.

template<typename Iter, typename Func>
void pair_wise(Iter it, Iter last, Func func) {
while(it != last) {
Iter other = it;
++other;
while(other != last) {
func(*it, *other);
++other;
}
++it;
}
}


Usage:

#include <iostream>
#include <vector>

int main() {
std::vector<int> values = {1, 2, 3, 4};

pair_wise(values.begin(), values.end(),
[](int& lhs, int& rhs) {
std::cout << "(" << lhs << ", " << rhs << ")\n";
});
}


Output:

(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)


You could do this:

template<typename Iter, typename Func>
void combine_pairwise(Iter first, Iter last, Func func)
{
for(; first != last; ++first)
std::for_each(std::next(first), last, std::bind(func, *first, std::placeholders::_1));
}


but if I was doing this in real code I would opt not to. The above is basically just being complicated for the hell of it. I would write the following in real code:

template<typename Iter, typename Func>
void combine_pairwise(Iter first, Iter last, Func func)
{
for(; first != last; ++first)
for(Iter next = std::next(first); next != last; ++next)
func(*first, *next);
}

• I think the two for loops are clearer than my two while loops. Having the next makes it clearer that the inner loop is over an increasingly smaller sub-list. Mar 1, 2013 at 9:30
• @PeterWood I don't know why, but even seasoned C++ devs love to write iter i = begin; while(i != end){ /*...*/ ++i; } (or the equivalent) instead of using a for loop. I find it constantly in other people's code; And it's much harder to quickly understand what's going on (it's longer too). Mar 2, 2013 at 21:16
• Normally I would write a for loop, but as the iterators were passed in and no initialisation was necessary I just jumped straight to the condition: while. It doesn't feel quite right to have empty initialisation in the for, but having thought about it I prefer it to while, now. Mar 2, 2013 at 23:02

It would be possible to write as for_each call to a functor writing for_each again, but I don't think it would actually be shorter.

I don't think pair_wise is a good name. There are two many things that it could mean. I'd suggest something with combinations as it calls the function for all 2-combinations.

• Maybe pairwise_combinations. Feb 28, 2013 at 12:30
• Or combine_pairwise Feb 28, 2013 at 12:30
• @PeterWood: Yes, those are decent names. Feb 28, 2013 at 12:31