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),
S
and input 2 do you want all the combinations of 2 and each item ofS
in an array of array length 2? – Dwaynedweck