TransWikia.com

Finding all the 3-combinations of the output of for loops

Stack Overflow Asked on November 15, 2021

I feel like this is supposed to be very straightforward but I am unable to work it out.

I have a very simple piece of c++ code.

for (int k = 0; k < 2; ++k)
    {
        for (int a = 0; a < 4; ++a)
        {
            for (int b = 0; b < 4; ++b)
            {
                if (a != b)
                {
                    std::cout << "k: " << k  << " a: " << a  << " b: " << b  << "n";
                }
            }
        }

The output will have 24 lines like this

k: 0 a: 0 b: 1
k: 0 a: 0 b: 2
k: 0 a: 0 b: 3
k: 0 a: 1 b: 0
k: 0 a: 1 b: 2
k: 0 a: 1 b: 3
k: 0 a: 2 b: 0
k: 0 a: 2 b: 1
k: 0 a: 2 b: 3
k: 0 a: 3 b: 0
k: 0 a: 3 b: 1
k: 0 a: 3 b: 2
k: 1 a: 0 b: 1
k: 1 a: 0 b: 2
k: 1 a: 0 b: 3
k: 1 a: 1 b: 0
k: 1 a: 1 b: 2
k: 1 a: 1 b: 3
k: 1 a: 2 b: 0
k: 1 a: 2 b: 1
k: 1 a: 2 b: 3
k: 1 a: 3 b: 0
k: 1 a: 3 b: 1
k: 1 a: 3 b: 2

What I want is essentially 3 choice of those 24 lines of output. 24 choose 3 = 2024 lines of output without any additional library usage. I want to do some calculations based on 3 of those 24 lines at a time.

The equivalent python code

import itertools    
iterable = ["k: 0 a: 0 b: 1", "k: 0 a: 0 b: 2", "k: 0 a: 0 b: 3", "k: 0 a: 1 b: 0", "k: 0 a: 1 b: 2", "k: 0 a: 1 b: 3", "k: 0 a: 2 b: 0", "k: 0 a: 2 b: 1", "k: 0 a: 2 b: 3", "k: 0 a: 3 b: 0", "k: 0 a: 3 b: 1", "k: 0 a: 3 b: 2", "k: 1 a: 0 b: 1", "k: 1 a: 0 b: 2", "k: 1 a: 0 b: 3", "k: 1 a: 1 b: 0", "k: 1 a: 1 b: 2", "k: 1 a: 1 b: 3", "k: 1 a: 2 b: 0", "k: 1 a: 2 b: 1", "k: 1 a: 2 b: 3", "k: 1 a: 3 b: 0", "k: 1 a: 3 b: 1", "k: 1 a: 3 b: 2"]
a = list(itertools.combinations(iterable, 3))
print(a)

demonstrates what I want. I was wondering how to do this in C++ using just the for loops.

2 Answers

If value of k is varying and much larger than 3, we'll have to apply recursion. Till then 3 for loops works fine.

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<vector<int>> M;
    for (int k = 0; k < 2; ++k)
        for (int a = 0; a < 4; ++a)
            for (int b = 0; b < 4; ++b)
                if (a != b)
                    M.push_back(vector<int>({ k, a, b }));

    vector<vector<int>> res;
    for (int i = 0; i < (int)M.size() - 2; ++i)
        for (int j = i + 1; j < (int)M.size() - 1; ++j)
            for (int k = j + 1; k < (int)M.size(); ++k)
            {
                vector<int> temp;

                for (int e : M[i])
                    temp.push_back(e);
                for (int e : M[j])
                    temp.push_back(e);
                for (int e : M[k])
                    temp.push_back(e);
                res.push_back(temp);
            }

    for (const vector<int>& V : res)
    {
        for (int e : V)
            cout << e << ' ';
        cout << endl;
    }
}

Answered by srt1104 on November 15, 2021

To make things easier, I'd group a k, a and b value together into a single object. Let's call it a K-A-B object, or a kab:

struct kab {
    int k, a, b;
};

Then, I'd make an increment function that'll take a kab and give us the next kab in the sequence. This'll allow us to condense all three of your loops down into one and make it easier to iterate from any point in the sequence. That could look like:

kab increment(kab obj) {
    obj.b = (obj.b + 1) % (MAX_B + 1);
    if(obj.b == 0) {
        obj.a = (obj.a + 1) % (MAX_A + 1);
        if(obj.a == 0) {
            obj.k++;
        }
    }
 
    // Ensure a != b by incrementing again if they are
    if(obj.a == obj.b) {
        return increment(obj);
    }
 
    return obj;
}

Lastly, it's just a matter of doing the actual increments. Here's an example:

while(vals.k <= MAX_K) {
    kab vals2 = increment(vals);
    while(vals2.k <= MAX_K) {
        kab vals3 = increment(vals2);
        while(vals3.k <= MAX_K) {
            std::cout << "k: " << vals.k  << " a: " << vals.a  << " b: " << vals.b  << std::endl;
            std::cout << "k: " << vals2.k  << " a: " << vals2.a  << " b: " << vals2.b  << std::endl;
            std::cout << "k: " << vals3.k  << " a: " << vals3.a  << " b: " << vals3.b  << std::endl;
            std::cout << std::endl;

            vals3 = increment(vals3);
        }
        vals2 = increment(vals2);
    }
    vals = increment(vals);
}

See it run here: https://ideone.com/9cVHuG (note that that much output causes ideone to timeout. This should work fine locally).

Answered by scohe001 on November 15, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP