1

consider this arrays, e.g.

#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
   std::vector<char> ls(3); ls[0] = 'a'; ls[1] = 'b'; ls[2] = 'c';
   std::vector<char> us(3); us[0] = 'A'; us[1] = 'B'; us[2] = 'C';
   std::vector<int> ns(3);  ns[0] = 1;   ns[1] = 2;   ns[2] = 3;

   std::vector<char>::const_iterator lIt;
   std::vector<char>::const_iterator uIt;
   std::vector<int>::const_iterator nIt ;

   for(lIt = ls.begin(); lIt != ls.end();++lIt)
       for(uIt = us.begin();uIt != us.end();++uIt)
            for (nIt = ns.begin();nIt != ns.end();++nIt)
                std::cout << *lIt << *uIt << *nIt << "\n";

}

it produces every possible combination of three vectors "aA1,...,cC3". now, I want to change it in a way that during the running, program decide number of vectors to go through (one, two, or three) and generate combination of choosen vectors. or simply, it there any way to generate a block of nested loops during the running time?

Sami1202
  • 127
  • 1
  • 8
  • 2
    What problem are you actually trying to solve? This seems to be an XY problem. – Shoe Jan 26 '15 at 18:30
  • You don't want to think in terms of "generating blocks of loops at runtime". You probably want to think about how to compute start and end indexes at runtime for your loops to create the desired behavior. – Ben Zotto Jan 26 '15 at 18:35
  • oh I see, it's not clear. I'm going to edit it. – Sami1202 Jan 26 '15 at 18:37
  • From what this looks like, all you want to do is take the string "aA1bB2cC3" and take a combination of 3 from these characters `C(9,3)`. That doesn't require multiple sets of loops. – PaulMcKenzie Jan 26 '15 at 18:38
  • it is not possible without type elision (your vectors can have different types). Having a limited number of types N and an implementation without type elision· you and up with N * N * N *... implementations. –  Jan 26 '15 at 18:39
  • @Sami1202 - Rethink your problem. All you want to do is take a combination of `N` things taken `R` at a time, where `N` and `R` are determined at runtime. In your sample, `N=9`, `R=3`. http://stackoverflow.com/questions/2685501/next-permutation-for-combinations-or-subsets-in-powerset – PaulMcKenzie Jan 26 '15 at 18:44
  • Thanks everyone! I got the idea. – Sami1202 Jan 26 '15 at 18:50

3 Answers3

2

You can defined a recursive function along the lines of:

template<class Container>
Container combinations(Container last) {
    return last;
}

template<class Container, class... Containers>
Container combinations(Container curr, Containers... rest) {
    auto ret = Container();
    for (auto i : curr)
        for (auto j : combinations(rest...))
            ret.push_back(i + j);
    return ret;
}

and then simply have:

int n = /* number of vectors */;
switch (n) {
    case 1: print_vec(combinations(ls)); break;
    case 2: print_vec(combinations(ls, us)); break;
    case 3: print_vec(combinations(ls, us, ns)); break;
}

Live demo

assuming of course a simple print_vec function.

You can even customize combinations more, by passing a functor that is applied to combine two elements, instead of operator+, but that's up to what you need.

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • I edited it to work if one or more of containers are empty and it works fine except if the last container is empy, any suggestion?http://coliru.stacked-crooked.com/a/1b06d48d264f5f1e – Sami1202 Jan 28 '15 at 07:18
  • @Sami1202 Well, my code simulates the [cartesian product](http://en.wikipedia.org/wiki/Cartesian_product). So technically speaking it's working correctly by not showing anything if any of the containers is empty. I can't see how you can modify it to ignore empty containers easily (without too much added complexity). I'd just recommend to filter the containers that are empty before using it. – Shoe Jan 28 '15 at 07:30
0

Nope, you cannot generate a block of loops at runtime. But it is possible to achieve a similar effect using recursion. Something like this:

void emulateNestedLoops(vector<size_t>& counters, 
        const vector<pair<size_t, size_t>>& bounds, size_t depth) {
    if (depth == bounds.size()) {
        // The body of the innermost loop.
    } else {
        counters.push_back(0);
        for (size_t i = bounds[depth].first; i < bounds[depth].second; i++) {
            counters.back() = i;
            emulateNestedLoops(counters, bounds, depth + 1);
        }
        counters.pop_back();
    }
}
kraskevich
  • 18,368
  • 4
  • 33
  • 45
  • exactly I was thinking about recursion but at the same time I thought that every recursion could be converted to regular code, right? – Sami1202 Jan 26 '15 at 18:46
  • @Sami1202 Check [Loop unrolling](http://en.wikipedia.org/wiki/Loop_unrolling) and [tail-recursion](http://stackoverflow.com/questions/33923/what-is-tail-recursion) . – Emadpres Jan 26 '15 at 18:48
0

So you need to Iterate recursively.

This simple code can give you some hints:

std::vector<int> manyVector[N];
int currentIndexOfEachVector[N];

void Iterate(std::vector<int> &v, int depth)
{
    if(depth==N)
    {
        for(int i=0;i<N;i++)
            std::cout<< manyVector[i][currentIndexOfEachVector[i]];
        return;
    }
    //////////////////////////////////////////////////////////////////////////
    for ( int i=0 ; i< manyVector[depth].size() ; i++ )
    {
        Iterate(manyVector[depth+1], depth+1);
    }

}


int main()
{
    Iterate(manyVector[0], 0);
    return 0;
}

If you don't like that static N, you can just change the code and use vector of vector or allocate the manyVector dynamically.

Emadpres
  • 3,466
  • 2
  • 29
  • 44