Search code examples
c++vectorresizepush-back

Dynamically resizing and filling a vector of vectors in C++


I have a vector that will have an unknown number of rows and 3 columns. The vector should be constructed as follows: a statistical test is made, if it pass a threshold the vector should store infos about it. What I am doing is:

vector< vector < int > > validated_edge_list;
validated_edge_list.resize(1);
validated_edge_list.at(1).resize(3);

for(int i = 0; i < e ; i++)
{
    p = gsl_cdf_hypergeometric_P(edge_list[i][2],
                                 k_vec[edge_list[i][1]],
                                 M-k_vec[edge_list[i][1]],
                                 N_vec[edge_list[i][0]]); // n2_matrix[i][j] = M-k_matrix[i][j]

    if (p <= bonferroni_lvl)
    {
        validated_edge_list[c][0] = edge_list[i][0];
        validated_edge_list[c][1] = edge_list[i][1];
        validated_edge_list[c][2] = edge_list[i][2];
        c = c + 1;
        validated_edge_list.resize(c+1);
        validated_edge_list.at(c+1).resize(3);
    }
}

As you can see I am manually adding a new raw each time. It gives me the following error:

terminate called after throwing an instance of 'std::out_of_range'
what():  vector::_M_range_check: __n (which is 1) >= this->size() (which is 1)
Aborted (core dumped)

I can assume that I am doing something wrong and I also think that I should use the push_back option, but I don't know how.

How can I fix this? (I am new with C++.)


Solution

  • Like you said, you should use push_back. Do not use resize. push_back is made to add an element to your vector and takes care of everything. resize, however, just increases or decreases your vector's capacity.

    Possible solution: (I haven't tested it, but this should give you the general idea)

    vector< vector < int > > validated_edge_list;
    
    for(int i = 0; i < e ; i++)
    { 
        p = gsl_cdf_hypergeometric_P (edge_list[i][2],k_vec[edge_list[i][1]],M-k_vec[edge_list[i][1]],N_vec[edge_list[i][0]]); // n2_matrix[i][j] = M-k_matrix[i][j]
        if (p <= bonferroni_lvl)
        {
            vector<int> single_edge_list = vector<int>(3); // Create a vector a 3 int's
            single_edge_list[0] = edge_list[i][0] ; // Fill the vector.
            single_edge_list[1] = edge_list[i][1] ; // Fill the vector.
            single_edge_list[2] = edge_list[i][2] ; // Fill the vector.
    
            validated_edge_list.push_back(single_edge_list); // Add it to validated_edge_list.
            c++; // You don't really need this anymore
        }
    
    }
    

    Note that, since the vectors inside validated_edge_list all have a length of 3, you don't need to use a vector of vectors, you could just use a structure (or class) that you could call EdgeList. It's not necessary, however.

    EDIT : You could find more efficient and better ways of doing the same thing (like YSC did below), but if you're a beginner working on a small program and you don't really mind reducing efficiency then this should be easy to program and good enough.