this is a recursive method, which you can use on any type. you can iterate on an instance of Combinations class (e.g. or get() vector with all combinations, each combination is a vector of objects. This is written in C++11.
//combinations.hpp #include <vector> template<typename T> class Combinations { // Combinations(std::vector<T> s, int m) iterate all Combinations without repetition // from set s of size m s = {0,1,2,3,4,5} all permuations are: {0, 1, 2}, {0, 1,3}, // {0, 1, 4}, {0, 1, 5}, {0, 2, 3}, {0, 2, 4}, {0, 2, 5}, {0, 3, 4}, {0, 3, 5}, // {0, 4, 5}, {1, 2, 3}, {1, 2, 4}, {1, 2, 5}, {1, 3, 4}, {1, 3, 5}, {1, 4, 5}, // {2, 3, 4}, {2, 3, 5}, {2, 4, 5}, {3, 4, 5} public: Combinations(std::vector<T> s, int m) : M(m), set(s), partial(std::vector<T>(M)) { N = s.size(); // unsigned long can't be casted to int in initialization out = std::vector<std::vector<T>>(comb(N,M), std::vector<T>(M)); // allocate space generate(0, N-1, M-1); }; typedef typename std::vector<std::vector<T>>::const_iterator const_iterator; typedef typename std::vector<std::vector<T>>::iterator iterator; iterator begin() { return out.begin(); } iterator end() { return out.end(); } std::vector<std::vector<T>> get() { return out; } private: void generate(int i, int j, int m); unsigned long long comb(unsigned long long n, unsigned long long k); // C(n, k) = n! / (n-k)! int N; int M; std::vector<T> set; std::vector<T> partial; std::vector<std::vector<T>> out; int count (0); }; template<typename T> void Combinations<T>::generate(int i, int j, int m) { // combination of size m (number of slots) out of set[i..j] if (m > 0) { for (int z=i; z<j-m+1; z++) { partial[M-m-1]=set[z]; // add element to permutation generate(z+1, j, m-1); } } else { // last position for (int z=i; z<j-m+1; z++) { partial[M-m-1] = set[z]; out[count++] = std::vector<T>(partial); // add to output vector } } } template<typename T> unsigned long long Combinations<T>::comb(unsigned long long n, unsigned long long k) { // this is from Knuth vol 3 if (k > n) { return 0; } unsigned long long r = 1; for (unsigned long long d = 1; d <= k; ++d) { r *= n--; r /= d; } return r; }
Test file:
// test.cpp // compile with: gcc -O3 -Wall -std=c++11 -lstdc++ -o test test.cpp #include <iostream> #include "combinations.hpp" struct Bla{ float x, y, z; }; int main() { std::vector<int> s{0,1,2,3,4,5}; std::vector<Bla> ss{{1, .4, 5.0},{2, .7, 5.0},{3, .1, 2.0},{4, .66, 99.0}}; Combinations<int> c(s,3); // iterate over all combinations for (auto x : c) { for (auto ii : x) std::cout << ii << ", "; std::cout << "\n"; } // or get a vector back std::vector<std::vector<int>> z = c.get(); std::cout << "\n\n"; Combinations<Bla> cc(ss, 2); // combinations of arbitrary objects for (auto x : cc) { for (auto b : x) std::cout << "(" << b.x << ", " << b.y << ", " << b.z << "), "; std::cout << "\n"; } }
output is :
0, 1, 2, 0, 1, 3, 0, 1, 4, 0, 1, 5, 0, 2, 3, 0, 2, 4, 0, 2, 5, 0, 3, 4, 0, 3, 5, 0, 4, 5, 1, 2, 3, 1, 2, 4, 1, 2, 5, 1, 3, 4, 1, 3, 5, 1, 4, 5, 2, 3, 4, 2, 3, 5, 2, 4, 5, 3, 4, 5,
(1, 0.4, 5), (2, 0.7, 5), (1, 0.4, 5), (3, 0.1, 2), (1, 0.4, 5), (4, 0.66, 99), (2, 0.7, 5), (3, 0.1, 2), (2, 0.7, 5), (4, 0.66, 99), (3, 0.1, 2), (4, 0.66, 99),
Sand input 2 do you want all the combinations of 2 and each item ofSin an array of array length 2?