A custom container with a bi-directional custom iterator for iterating over all combinations of elements from multiple sets.
Some implementation details:
- The container does not store all the combinations
- Combinations are calculated on the fly when iterator is incremented or decremented
- Combination is represented as a vector of iterators: one for each set
- When combinations iterator is dereferenced or arrow operator is called, combination is returned by value to avoid dangling
- c++98 compatible
// Precondition: all sets between iterators should be non-empty:
// contain at least 1 element
template <typename SetsIter>
class combinations
{
public:
typedef combinations<SetsIter> Combinations_type;
typedef typename std::iterator_traits<SetsIter>::value_type Set;
typedef typename std::vector<typename Set::const_iterator> Combination;
typedef Combination value_type;
typedef long long difference_type;
typedef size_t size_type;
class const_iterator
{
public:
typedef std::bidirectional_iterator_tag iterator_category;
typedef typename Combinations_type::difference_type difference_type;
typedef typename Combinations_type::value_type value_type;
typedef const Combination reference;
typedef const Combination pointer;
const_iterator() {}
const_iterator(const const_iterator& other);
const_iterator(SetsIter first, SetsIter last, Combination combination);
static const_iterator make_begin(const SetsIter first, const SetsIter last);
static const_iterator make_end(const SetsIter first, const SetsIter last);
~const_iterator() {}
const_iterator& operator=(const const_iterator other);
bool operator==(const const_iterator& other) const;
bool operator!=(const const_iterator& other) const;
const_iterator& operator++();
const_iterator& operator--();
Combination operator*() const;
Combination operator->() const;
friend void swap(const_iterator& first, const_iterator& second);
void swap(Combinations_type other);
};
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
combinations();
combinations(SetsIter first, SetsIter last);
combinations(const combinations<SetsIter>& other);
~combinations();
combinations& operator=(const combinations<SetsIter>& other);
bool operator==(const combinations<SetsIter>& other) const;
bool operator!=(const combinations<SetsIter>& other) const;
const_iterator cbegin() const;
const_iterator begin() const;
const_iterator cend() const;
const_iterator end() const;
const_reverse_iterator crbegin() const;
const_reverse_iterator rbegin() const;
const_reverse_iterator crend() const;
const_reverse_iterator rend() const;
friend void swap(combinations<SetsIter>& first, combinations<SetsIter>& second);
void swap(combinations<SetsIter> other);
size_type size() const;
size_type max_size() const;
bool empty() const;
};
template <typename Sets>
combinations<typename Sets::const_iterator> make_combinations(const Sets& data);
#include <algorithm>
#include <iostream>
#include "combinations.hpp"
int main()
{
typedef std::vector<int> Set;
typedef std::vector<Set> SetOfSets;
typedef SetOfSets::const_iterator SetOfSetsCIt;
const SetOfSets data = {{2, 4}, {1, 3, 8}, {7, 5}};
{
std::cout << "First to last-------" << std::endl;
typedef combinations<SetOfSetsCIt> Combinations;
Combinations cmbs = make_combinations(data);
{
std::cout << "Forward:" << std::endl;
for(const auto& combination : cmbs)
{
for(const auto& elemIt : combination)
std::cout << *elemIt << " ";
std::cout << std::endl;
}
}
{
std::cout << "Reverse:" << std::endl;
for(Combinations::const_reverse_iterator combIt = cmbs.crbegin();
combIt != cmbs.crend();
++combIt)
{
for(const auto& elemIt : *combIt)
std::cout << *elemIt << " ";
std::cout << std::endl;
}
}
}
{
std::cout << "Last to first-------" << std::endl;
typedef SetOfSets::const_reverse_iterator SetOfSetsCRIt;
typedef combinations<SetOfSetsCRIt> Combinations;
Combinations cmbs(data.crbegin(), data.crend());
{
std::cout << "Forward:" << std::endl;
for(Combinations::const_iterator cmbIt = cmbs.begin();
cmbIt != cmbs.end();
++cmbIt)
{
Combinations::Combination c = *cmbIt;
std::reverse(c.begin(), c.end());
for(const auto& it : c)
std::cout << *it << " ";
std::cout << std::endl;
}
}
{
std::cout << "Reverse:" << std::endl;
for(Combinations::const_reverse_iterator cmbIt = cmbs.crbegin();
cmbIt != cmbs.crend();
++cmbIt)
{
Combinations::Combination c = *cmbIt;
std::reverse(c.begin(), c.end());
for(const auto& it : c)
std::cout << *it << " ";
std::cout << std::endl;
}
}
}
}
First to last-------
Forward:
2 1 7
4 1 7
2 3 7
4 3 7
2 8 7
4 8 7
2 1 5
4 1 5
2 3 5
4 3 5
2 8 5
4 8 5
Reverse:
4 8 5
2 8 5
4 3 5
2 3 5
4 1 5
2 1 5
4 8 7
2 8 7
4 3 7
2 3 7
4 1 7
2 1 7
Last to first-------
Forward:
2 1 7
2 1 5
2 3 7
2 3 5
2 8 7
2 8 5
4 1 7
4 1 5
4 3 7
4 3 5
4 8 7
4 8 5
Reverse:
4 8 5
4 8 7
4 3 5
4 3 7
4 1 5
4 1 7
2 8 5
2 8 7
2 3 5
2 3 7
2 1 5
2 1 7