Howto Create Combinations of Several Vectors Without Hardcoding Loops in C++

Howto create combinations of several vectors without hardcoding loops in C++?

This will do the trick:

void printAll(const vector<vector<string> > &allVecs, size_t vecIndex, string strSoFar)
{
if (vecIndex >= allVecs.size())
{
cout << strSoFar << endl;
return;
}
for (size_t i=0; i<allVecs[vecIndex].size(); i++)
printAll(allVecs, vecIndex+1, strSoFar+allVecs[vecIndex][i]);
}

Call with:

printAll(allVecs, 0, "");

Create all possible combinations of multiple vectors

Rather than a recursive function (which works, but can be clumsy in practice) I prefer to treat this as a simple problem of counting.

Let's start with a simplifying assumption: that we have 3 arrays of 10 elements apiece. In this case, it's obvious that we can print out all combinations simply by counting from 0 (which we'd think of as 000) to 999, and using each digit as a subscript into the appropriate sub-vector.

There's no magic to having 10 items per sub-vector, or having the same number of items in each sub-vector. It just happens that with 10 items apiece, the index into each array corresponds to the digits we're accustomed to seeing/using in base 10 numbers.

When we're dealing with base 10 numbers, we can use the remainder after division by 10 to get each digit we need. For the task at hand, we can do roughly the same, except that we use division by the number of elements in a sub-array instead.

So, let's start by computing the number of combinations in the inputs (for the moment, we'll assume each sub-vector has a non-zero size):

size_t max = 1;

for (auto const &v : allVecs)
max *= v.size();

Then we simply count from 0 to max, take the remainder after dividing by the respective vector size, and using those to index into the sub-vectors:

for (size_t i=0; i<max; i++) {
auto temp = i;
for (auto const &vec : allVecs) {
auto index = temp % vec.size();
temp /= vec.size();
std::cout << vec[index] << ' ';
}
std::cout << '\n';
}

As it stands right now, this has one point that might find confusing or problematic: it prints out the results in the reverse of the order you might expect. For example, instead of the 1 5 11 you show as the first output, it would show 11 5 1. If this is unacceptable, there are a number of easy ways to rectify the situation. The easiest is probably to start by simply reversing the input vector:

std::reverse(allVecs.begin(), allVecs.end());

If you have any hope of generating the combinations to ever finish, the input vector is going to be small enough for this O(N) operation to have little effect on anything.

How can I create combinations of several lists without hardcoding loops?

I would recommend Set::CrossProduct, which will create an iterator to yield the cross product of all of your sets. Because it uses an iterator, it does not need to generate every combination in advance; rather, it yields each one on demand.

use strict;
use warnings;
use Set::CrossProduct;

my @homopol = (
[qw(T C CC G)],
[qw(T TT C G A)],
[qw(C CCC G)],
);

my @prob = (
[1.00,0.63,0.002,1.00],
[0.72,0.03,1.00, 0.85,1.00],
[1.00,0.97,0.02],
);

# Prepare by storing the data in a list of lists of pairs.
my @combined;
for my $i (0 .. $#homopol){
push @combined, [];
push @{$combined[-1]}, [$homopol[$i][$_], $prob[$i][$_]]
for 0 .. @{$homopol[$i]} - 1;
};

my $iterator = Set::CrossProduct->new([ @combined ]);
while( my $tuple = $iterator->get ){
my @h = map { $_->[0] } @$tuple;
my @p = map { $_->[1] } @$tuple;
my $product = 1;
$product *= $_ for @p;
print join('-', @h), ' ', join(' x ', @p), ' = ', $product, "\n";
}

Create all possible combinations from two values for each element in a vector in R

expand.grid is a function that makes all combinations of whatever vectors you pass it, but in this case you need to rearrange your vectors so you have a pair of first elements, second elements, and third elements so the ultimate call is:

expand.grid(c(6, 12), c(2, 5), c(9, 15))

A quick way to rearrange the vectors in base R is Map, the multivariate version of lapply, with c() as the function:

a <- c(6, 2, 9)
b <- c(12, 5, 15)

Map(c, a, b)

## [[1]]
## [1] 6 12
##
## [[2]]
## [1] 2 5
##
## [[3]]
## [1] 9 15

Conveniently expand.grid is happy with either individual vectors or a list of vectors, so we can just call:

expand.grid(Map(c, a, b))

## Var1 Var2 Var3
## 1 6 2 9
## 2 12 2 9
## 3 6 5 9
## 4 12 5 9
## 5 6 2 15
## 6 12 2 15
## 7 6 5 15
## 8 12 5 15

If Map is confusing you, if you put a and b in a list, purrr::transpose will do the same thing, flipping from a list of two elements of length three to a list of three elements of length two:

library(purrr)

list(a, b) %>% transpose() %>% expand.grid()

and return the same thing.

How can I create cartesian product of vector of vectors?

First, I'll show you a recursive version.

// Cartesion product of vector of vectors

#include <vector>
#include <iostream>
#include <iterator>

// Types to hold vector-of-ints (Vi) and vector-of-vector-of-ints (Vvi)
typedef std::vector<int> Vi;
typedef std::vector<Vi> Vvi;

// Just for the sample -- populate the intput data set
Vvi build_input() {
Vvi vvi;

for(int i = 0; i < 3; i++) {
Vi vi;
for(int j = 0; j < 3; j++) {
vi.push_back(i*10+j);
}
vvi.push_back(vi);
}
return vvi;
}

// just for the sample -- print the data sets
std::ostream&
operator<<(std::ostream& os, const Vi& vi)
{
os << "(";
std::copy(vi.begin(), vi.end(), std::ostream_iterator<int>(os, ", "));
os << ")";
return os;
}
std::ostream&
operator<<(std::ostream& os, const Vvi& vvi)
{
os << "(\n";
for(Vvi::const_iterator it = vvi.begin();
it != vvi.end();
it++) {
os << " " << *it << "\n";
}
os << ")";
return os;
}

// recursive algorithm to to produce cart. prod.
// At any given moment, "me" points to some Vi in the middle of the
// input data set.
// for int i in *me:
// add i to current result
// recurse on next "me"
//
void cart_product(
Vvi& rvvi, // final result
Vi& rvi, // current result
Vvi::const_iterator me, // current input
Vvi::const_iterator end) // final input
{
if(me == end) {
// terminal condition of the recursion. We no longer have
// any input vectors to manipulate. Add the current result (rvi)
// to the total set of results (rvvvi).
rvvi.push_back(rvi);
return;
}

// need an easy name for my vector-of-ints
const Vi& mevi = *me;
for(Vi::const_iterator it = mevi.begin();
it != mevi.end();
it++) {
// final rvi will look like "a, b, c, ME, d, e, f"
// At the moment, rvi already has "a, b, c"
rvi.push_back(*it); // add ME
cart_product(rvvi, rvi, me+1, end); add "d, e, f"
rvi.pop_back(); // clean ME off for next round
}
}

// sample only, to drive the cart_product routine.
int main() {
Vvi input(build_input());
std::cout << input << "\n";

Vvi output;
Vi outputTemp;
cart_product(output, outputTemp, input.begin(), input.end());
std::cout << output << "\n";
}

Now, I'll show you the recursive iterative version that I shamelessly stole from @John :

The rest of the program is pretty much the same, only showing the cart_product function.

// Seems like you'd want a vector of iterators
// which iterate over your individual vector<int>s.
struct Digits {
Vi::const_iterator begin;
Vi::const_iterator end;
Vi::const_iterator me;
};
typedef std::vector<Digits> Vd;
void cart_product(
Vvi& out, // final result
Vvi& in) // final result

{
Vd vd;

// Start all of the iterators at the beginning.
for(Vvi::const_iterator it = in.begin();
it != in.end();
++it) {
Digits d = {(*it).begin(), (*it).end(), (*it).begin()};
vd.push_back(d);
}

while(1) {

// Construct your first product vector by pulling
// out the element of each vector via the iterator.
Vi result;
for(Vd::const_iterator it = vd.begin();
it != vd.end();
it++) {
result.push_back(*(it->me));
}
out.push_back(result);

// Increment the rightmost one, and repeat.

// When you reach the end, reset that one to the beginning and
// increment the next-to-last one. You can get the "next-to-last"
// iterator by pulling it out of the neighboring element in your
// vector of iterators.
for(Vd::iterator it = vd.begin(); ; ) {
// okay, I started at the left instead. sue me
++(it->me);
if(it->me == it->end) {
if(it+1 == vd.end()) {
// I'm the last digit, and I'm about to roll
return;
} else {
// cascade
it->me = it->begin;
++it;
}
} else {
// normal
break;
}
}
}
}

Implementing an iterator over combinations of many vectors

Why would you like to use custom iterators?
One could instead implement a very simple class that will iterate through all combinations:

class Combinator
{
public:
Combinator(std::vector<std::vector<int> >& vectors)
: m_vectors(vectors)
{
m_combination.reserve(m_vectors.size());
for(auto& v : m_vectors)
m_combination.push_back(v.begin());
}

bool next()
{
// iterate through vectors in reverse order
for(long long i = m_vectors.size() - 1; i >= 0; --i)
{
std::vector<int>& v = m_vectors[i];
std::vector<int>::iterator& it = m_combination[i];

if(++it != v.end())
return true;
it = v.begin();
}
return false;
}

std::vector<std::vector<int>::iterator> combination() const
{
return m_combination;
}

private:
std::vector<std::vector<int> >& m_vectors; // reference to data
std::vector<std::vector<int>::iterator> m_combination;
};

Live Demo

UPDATE:
If you would still like to use iterators, I suggest iterating over combinations. One can put all the combinations from Combinator into a container and then work with container's own iterators. In my opinion it's a cleaner solution. The only drawback is the extra-memory needed to store all combinations explicitly.

Generating combinations in c++

A simple way using std::next_permutation:

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
int n, r;
std::cin >> n;
std::cin >> r;

std::vector<bool> v(n);
std::fill(v.end() - r, v.end(), true);

do {
for (int i = 0; i < n; ++i) {
if (v[i]) {
std::cout << (i + 1) << " ";
}
}
std::cout << "\n";
} while (std::next_permutation(v.begin(), v.end()));
return 0;
}

or a slight variation that outputs the results in an easier to follow order:

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
int n, r;
std::cin >> n;
std::cin >> r;

std::vector<bool> v(n);
std::fill(v.begin(), v.begin() + r, true);

do {
for (int i = 0; i < n; ++i) {
if (v[i]) {
std::cout << (i + 1) << " ";
}
}
std::cout << "\n";
} while (std::prev_permutation(v.begin(), v.end()));
return 0;
}

A bit of explanation:

It works by creating a "selection array" (v), where we place r selectors, then we create all permutations of these selectors, and print the corresponding set member if it is selected in in the current permutation of v. Hope this helps.



Related Topics



Leave a reply



Submit