Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate on unordered pairs inside an unordered_set?

What's a concise way to iterate on unordered-pairs of elements in unordered_set?

(So order doesn't matter and elements should be different)

e.g. {1, 2, 3} => (1, 2) (2, 3) (1, 3)

My initial attempts were something like

for (i = 0; i < size - 1; i++) {
  for (j = i + 1; j < size; j++) {
    ...
  }
}

But that's not super-convenient with iterators.

like image 931
Uri Avatar asked Jan 25 '16 17:01

Uri


People also ask

How do you iterate over an unordered set?

Methods of unordered_set:begin()– Return an iterator pointing to the first element in the unordered_set container. end()– Returns an iterator pointing to the past-the-end-element. count()– Count occurrences of a particular element in an unordered_set container. find()– Search for an element in the container.

Can we insert pair in unordered_set C++?

An unordered set of pairs is an unordered set in which each element is a pair itself. By default, C++ doesn't allow us to create an unordered set of pairs directly but one can pass a hash function to the unordered set container.

Is unordered_set faster than set?

set uses less memory than unordered_set to store the same number of elements. For a small number of elements, lookups in a set might be faster than lookups in an unordered_set . That set sorts the elements is useful if you want to access them in order.

Does unordered set allow duplicates C++?

Unordered sets do not allow duplicates and are initialized using comma-delimited values enclosed in curly braces.


2 Answers

This should work, given an std::unordered_set s:

auto set_end = s.end();
for (auto ai = s.begin(); ai != set_end; ++ai) {
    for (auto bi = std::next(ai); bi != set_end; ++bi) {
        // *ai, *bi
    }
}

This is basically the iterator equivalent of the following in integers:

for (int i = 0; i < n; ++i) {
    for (int j = i + 1; j < n; ++j) {
        // i, j
    }
}
like image 97
orlp Avatar answered Oct 08 '22 11:10

orlp


Here is orlp's solution in semi-generic form.

template<typename ForwardIterator, typename DestItr>
auto cartesian_product(ForwardIterator b, ForwardIterator e, DestItr d) -> DestItr {
    using std::next;
    using std::for_each;
    for (; b != e; ++b) {
        for_each(next(b), e, [&](auto right){
            *d++ = std::make_tuple(*b, right);
        });
    }
    return d;
}

template<typename ForwardRange, typename DestItr>
auto cartesian_product(ForwardRange r, DestItr d) -> DestItr {
    using std::begin;
    using std::end;
    return cartesian_product(begin(r), end(r), d);
}

Live on Coliru.

You could, of course, make it more generic by having overloads for custom functors to use instead of make_tuple and the assignment operator. The standard library algorithms tend to do so. Were I writing this for a library, I'd probably do so as well.

like image 20
caps Avatar answered Oct 08 '22 10:10

caps