Creating N nested for-loops

后端 未结 7 1941
终归单人心
终归单人心 2020-12-03 11:16

Is there a way to create for-loops of a form

for(int i = 0; i < 9; ++i) {
    for(int j = 0; j < 9; ++i) {
    //...
        for(int k = 0; k < 9; +         


        
相关标签:
7条回答
  • 2020-12-03 11:26

    Here is a nice little class for a multi-index that can be iterated via a range-based for-loop:

    #include<array>
    
    template<int dim>
    struct multi_index_t
    {
        std::array<int, dim> size_array;
        template<typename ... Args>
        multi_index_t(Args&& ... args) : size_array(std::forward<Args>(args) ...) {}
    
        struct iterator
        {
            struct sentinel_t {};
    
            std::array<int, dim> index_array = {};
            std::array<int, dim> const& size_array;
            bool _end = false;
    
            iterator(std::array<int, dim> const& size_array) : size_array(size_array) {}
    
            auto& operator++()
            {
                for (int i = 0;i < dim;++i)
                {
                    if (index_array[i] < size_array[i] - 1)
                    {
                        ++index_array[i];
                        for (int j = 0;j < i;++j)
                        {
                            index_array[j] = 0;
                        }
                        return *this;
                    }
                }
                _end = true;
                return *this;
            }
            auto& operator*()
            {
                return index_array;
            }
            bool operator!=(sentinel_t) const
            {
                return !_end;
            }
        };
    
        auto begin() const
        {
            return iterator{ size_array };
        }
        auto end() const
        {
            return typename iterator::sentinel_t{};
        }
    };
    
    template<typename ... index_t>
    auto multi_index(index_t&& ... index)
    {
        static constexpr int size = sizeof ... (index_t); 
        auto ar = std::array<int, size>{std::forward<index_t>(index) ...};
        return multi_index_t<size>(ar);
    }
    

    The basic idea is to use an array that holds a number of dim indices and then implement operator++ to increase these indices appropriately.

    Use it as

    for(auto m : multi_index(3,3,4))
    {
        // now m[i] holds index of i-th loop
        // m[0] goes from 0 to 2
        // m[1] goes from 0 to 2
        // m[2] goes from 0 to 3
        std::cout<<m[0]<<" "<<m[1]<<" "<<m[2]<<std::endl;
    }
    

    Live On Coliru

    0 讨论(0)
  • 2020-12-03 11:29

    I use this solution:

    unsigned int dim = 3;
    unsigned int top = 5;
    std::vector<unsigned int> m(dim, 0);
    for (unsigned int i = 0; i < pow(top,dim); i++)
    {
        // What you want to do comes here 
        //      |
        //      |
        //      v
        // -----------------------------------
        for (unsigned int j = 0; j < dim; j++)
        {
            std::cout << m[j] << ",";
        }
        std::cout << std::endl;
        // -----------------------------------
    
        // Increment m
        if (i == pow(top, dim) - 1) break;
        unsigned int index_to_increment = dim - 1;
        while(m[index_to_increment] == (top-1)) {
            m[index_to_increment] = 0;
            index_to_increment -= 1;
        }
        m[index_to_increment] += 1;
    }
    

    It can certainly optimized and adapted, but it works quite well and you don't need to pass parameters to a recursive function. With a separate function to increment the multi-index:

    typedef std::vector<unsigned int> ivec;
    void increment_multi_index(ivec &m, ivec const & upper_bounds)
    {
        unsigned int dim = m.size();
        unsigned int i = dim - 1;
        while(m[i] == upper_bounds[i] - 1 && i>0) {
            m[i] = 0;
            i -= 1;
        }
        m[i] += 1;
    }
    
    int main() {
    
        unsigned int dim = 3;
        unsigned int top = 5;
        ivec m(dim, 0);
        ivec t(dim, top);
        for (unsigned int i = 0; i < pow(top,dim); i++)
        {
            // What you want to do comes here 
            //      |
            //      |
            //      v
            // -----------------------------------
            for (unsigned int j = 0; j < dim; j++)
            {
                std::cout << m[j] << ",";
            }
            std::cout << std::endl;
            // -----------------------------------
    
            // Increment m
            increment_multi_index(m, t);
        }
    
    }
    
    0 讨论(0)
  • 2020-12-03 11:41

    I'm going to take the OP at face value on the example code that was given, and assume what's being asked for is a solution that counts through an arbitrary base-10 number. (I'm basing this on the comment "Ideally I'm trying to figure out a way to loop through seperate elements of a vector of digits to create each possible number".

    This solution has a loop that counts through a vector of digits in base 10, and passes each successive value into a helper function (doThingWithNumber). For testing purposes I had this helper simply print out the number.

    #include <iostream>
    
    using namespace std;
    
    void doThingWithNumber(const int* digits, int numDigits)
    {
        int i;
        for (i = numDigits-1; i>=0; i--)
            cout << digits[i];
        cout << endl;
    }
    
    void loopOverAllNumbers(int numDigits)
    {
        int* digits = new int [numDigits];
        int i;
        for (i = 0; i< numDigits; i++) 
            digits[i] = 0;
    
        int maxDigit = 0;
        while (maxDigit < numDigits) {
            doThingWithNumber(digits, numDigits);
            for (i = 0; i < numDigits; i++) {
                digits[i]++;
                if (digits[i] < 10)
                    break;
                digits[i] = 0;
            }
            if (i > maxDigit)
                maxDigit = i;
        }
    }
    
    int main()
    {
        loopOverAllNumbers(3);
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-03 11:43

    You could use a recursive function:

    void loop_function(/*params*/,int N){
    for(int i=0;i<9;++i){
        if(N>0) loop_function(/*new params*/,N-1);
    }
    

    This will call recursively to loop_function N times, while each function will iterate calling loop_function

    It may be a bit harder to program this way, but it should do what you want

    0 讨论(0)
  • 2020-12-03 11:43

    You can use recursive call as:

    void runNextNestedFor(std::vector<int> counters, int index)
    {
         for(counters[index] = 0; counters[index] < 9; ++counters[index]) {
           // DO
           if(index!=N)
              runNextNestedFor(counters, index+1);
         }
    }
    

    Call it first time as:

    std::vectors<int> counters(N);
    runNextNestedFor(counters, 0);
    
    0 讨论(0)
  • 2020-12-03 11:47

    You may use recursion instead with a base condition -

    void doRecursion(int baseCondition){
    
       if(baseCondition==0) return;
    
       //place your code here
    
       doRecursion(baseCondition-1);
    }  
    

    Now you don't need to provide the baseCondition value at compile time. You can provide it while calling the doRecursion() method.

    0 讨论(0)
提交回复
热议问题