获取C ++中多维数组元素的所有组合

时间:2017-04-15 20:26:21

标签: c++ algorithm matrix nested-loops

想象一下包含以下元素的3行3列矩阵:

     [,1] [,2] [,3]   
[1,]    1    4    7   
[2,]    2    5    8
[3,]    3    6    9

我想编写一个函数来提取triples的每个组合,其中第一个元素来自column1,第二个元素来自第2列等。第一个这样的三元组可能是

1,4,7, then
1,4,8
1,4,9
1,5,7
1,5,8 and so on

每个三元组应该是另一个函数的参数。在该示例中,通常存在27个这样的三元组,行^列。

虽然对于这个例子,我可以编写3个嵌套for循环迭代三列,我想有一个函数可以处理任何n行和m列的矩阵。

在R中,有expand.grid函数可用于此但我希望有一个简单的C ++解决方案(不调用Rcpp)。

如果我有:

std::vector<double> col1 = {1,2,3};         
std::vector<double> col2 = {4,5,6};
std::vector<double> col3 = {7,8,9};
std::vector<std::vector<double>> matrix = {col1,col2,col3};

std::vector<std::vector<double>> result = generateGrid(matrix);
// result should contain [[1,4,7], [1,4,8], etc];

2 个答案:

答案 0 :(得分:1)

如果我做对了,你的问题就像打印所有n元组一样,其中每个元素都在[0,m]中,然后它将成为m,n矩阵的索引。这可以通过递归轻松完成:

使用范围[0,m)中的元素打印所有n元组:

for each number from [0,m):
 1. print number
 2. print all (n-1)-tuples with elements from range [0,m)

可以将其翻译成以下代码:

#include <vector>
#include <iostream>

using row_t = std::vector<double>;
using matrix_t = std::vector<row_t>;


void function_impl(size_t col, size_t row, const size_t numCols, const size_t numRows, row_t& rBuff, const matrix_t& m, matrix_t& result)
{
    rBuff[col] = m[row][col];

    if (col == numCols - 1)//If we've filled the permutation, append it to result
        result.push_back(rBuff);
    else//Fill rest of row with all possible combinations
    {
        for (size_t r = 0; r < numRows; ++r)
            function_impl(col + 1, r, numCols, numRows, rBuff, m, result);
    }
}

matrix_t function(const matrix_t& m)
{
    size_t numRows = m[0].size();//Assumes rectangular matrix
    size_t numCols = m.size();

    matrix_t result;
    row_t rowBuffer(numCols);//Buffer to store current permutation of indices

    //Places all possible indices into first element of permutation and recurses
    for (size_t r = 0; r < numRows; ++r)
        function_impl(0, r, numCols, numRows, rowBuffer, m, result);
    return result;
}



int main()
{
    row_t col1 = {1,2,3};
    row_t col2 = {4,5,6};
    row_t col3 = {7,8,9};
    matrix_t matrix = {col1,col2,col3};

    //Prints all 27 combinations
    for (const auto& row : function(matrix))
    {
        for (const auto& el : row)
            std::cout << el << " ";
        std::cout << '\n';
    }
    system("PAUSE");
}

它确实使用递归到具有常量一行内存的列数的深度。当然,生成的矩阵将包含m ^ n个元素,但是如果您只需要打印它们,您可以立即执行此操作,而不是追加到结果并一起删除结果矩阵。

答案 1 :(得分:0)


    
    #include <iostream>
    #include <vector>

    using namespace std;

    using matrix_t = vector < vector < double > >

    //class for simulating multiple for(int i=from ;i<=to;++i) in a row
    class multi_iterator
    {
    using Iterators = size_t*;


    private:
        Iterators iterators;   //array of iterators for multiple synchronized but different iterations
                               //through the same interval from-to

        size_t iter_amount;       //number of iterators in array above

        //all are iterating from - to
        size_t from;
        size_t to;



    public:
        multi_iterator(size_t number_of_iterators , size_t _from , size_t _to)
        {
            iter_amount = number_of_iterators;
            iterators = new size_t[number_of_iterators]();
            from = _from;
            to = _to;
        }


        int get_value(size_t iterator_id)// iter_id is the index of an iterator inside array iterators
        {
            return iterators[iterator_id];
        }


        int end()//if the last iterator is greater than "to" the iterations are over and the function returns true
        {
            if( iterators[iter_amount-1] >to )
                return true;

            else return false;
        }


        //increments in a synchronized order
        void operator++()
        {
            int iter_id = 0;

            while(iter_id < iter_amount)    //start the loop with the first iterator
            {
                if(iterators[iter_id] < to) //if the iterator didnt reach the upper boundary "to"
                {
                    ++iterators[iter_id];   //increment the iterator
                    break;
                }

                else if( iterators[iter_id] == to  )    //if the iterator reached the upper boundery "to"
                {
                    if( iter_id < iter_amount-1 )       //if it's not the last iterator
                    {
                        iterators[iter_id]=0;    //turn the iterator back to 0
                        ++iter_id;               //move on to the next iterator
                        continue;                //continue the loop with the next iterator
                    }

                    else                        //the last iterator reached the upper boundery
                    {

                        ++iterators[iter_id];   // the iterations are over
                        break;

                    }

                }


            }

        }


    };

    void function(const matrix_t& matrix)
    {
        size_t columns = matrix.size();

        if(columns > 0 )
        {
            size_t rows    = matrix[0].size();

            multi_iterator it(columns , 0 , rows-1 );//we need a row-iterator(from 0 to "row") for every column

            while( !it.end() )
            {
                for(size_t i=0;i < columns;++i)
                {
                    size_t iter_value_column_i = it.get_value(i);

                    cout<< matrix[i][ iter_value_column_i ]<<" ";
                }
                cout<<endl;
                ++it;
            }
        }
    }

    int main()
    {
        std::vector<double> col1 = {1,2};
        std::vector<double> col2 = {4,5};
        std::vector<double> col3 = {7,8};
        std::vector<std::vector<double>> matrix = {col1,col2,col3};



        function(matrix);


        return 0;
    }