2017-02-03 5 views
-2

У меня есть вектор, который будет иметь неизвестное количество строк и 3 столбца. Вектор должен быть сконструирован следующим образом: производится статистический тест, если он пропускает порог, вектор должен хранить информацию об этом. Что я делаю:Динамическое изменение размера и заполнение вектора векторов в C++

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); 
    } 
} 

Как вы можете видеть, я вручную добавлять новое сырец каждый раз. Это дает мне следующее сообщение об ошибке:

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) 

Я могу предположить, что я делаю что-то неправильно, и я также думаю, что я должен использовать опцию push_back, но я не знаю, как.

Как это исправить? (Я новичок в C++.)

+0

Пожалуйста, отредактируйте ваш вопрос, чтобы включить [mcve]. – YSC

+0

'c = c + 1;' может быть сокращен до 'C++;' Вы также можете избежать двух '+ 1' s, переместив их вниз после 'resize()' и 'at()'. –

ответ

0

Как вы сказали, вы должны использовать push_back. Не используйте resize. push_back создан, чтобы добавить элемент к вашему вектору и заботится обо всем. resize, однако, просто увеличивает или уменьшает емкость вашего вектора.

Возможное решение: (я не проверял, но это должно дать вам общее представление)

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 
    } 

} 

Обратите внимание, что, так как векторы внутри validated_edge_list все имеют длину 3, вы не Не нужно использовать вектор векторов, вы можете просто использовать structure (или класс), который вы могли бы назвать EdgeList. Однако это не обязательно.

EDIT: вы можете найти более эффективные и лучшие способы сделать то же самое (например, YSC, сделанные ниже), но если вы новичок, работающий над небольшой программой, и вы действительно не возражаете против эффективности, тогда это должно быть просты в программировании и достаточно хороши.

+0

Спасибо! Один вопрос: мне действительно нужно поставить 'vector single_edge_list = vector (3); // Создаем вектор 3 int's' внутри if?Почему я не могу объявить его только одним и перезаписать его, когда это необходимо? –

+0

@RiccardoMarcaccioli Рад, что я мог бы помочь. Что касается вашего вопроса, вы можете сделать то и другое. Однако многие профессиональные программисты скажут вам, что декларировать внутри лучше. Представьте, что у вас действительно сложная функция с большим количеством переменных. Если вы объявляете * все * переменные в верхней части и * затем * используйте их ниже, вам будет трудно запомнить, где они были объявлены. Вы видите переменную и спрашиваете: «Что это полезно снова?», Тогда вам нужно прокрутить весь путь, найти декларацию, понять ее, прокрутить назад и спросить себя: «А как насчет этого?», Идите резервное копирование и т. д. –

+0

Кроме того, если переменная объявлена ​​в верхней части, вам нужно найти функцию * whole *, чтобы увидеть, где эта переменная используется. Кто знает, может быть, среди 300 строк этой функции вы не видели немного «i ++» ... Принимая во внимание, что если вы объявляете как можно позже, вы на 100% уверены, что переменная не использовалась до этого был объявлен. Поэтому для понимания и отладки кода требуется гораздо меньше времени. (PS, представьте, если вы читали чей-то код, и они объявили свои переменные на всем пути! Вы не хотите, чтобы ваши товарищи по работе думали об этом * ваш * код, не так ли?) –

0

Я настоятельно рекомендую линеаризовать ваши данные внутри; вектор векторов дорог для работы (когда внешний вектор перемещает свою память, например), и это больно читать и писать код, который их использует.

Вот минимальная идея:

template<class T, std::size_t width> 
struct Matrix 
{ 
    Matrix(std::size_t height) { _data.reserve(width*height); } 
    const T& operator()(std::size_t i, std::size_t j) const { return _data[i*width+j]; } 
      T& operator()(std::size_t i, std::size_t j)  { return _data[i*width+j]; } 

private: 
    std::vector<T> _data; 
}; 

Usage example on coliru

+0

Я * полностью * согласен с вашим ответом, однако в случае с Риккардо кажется, что он только начинается с C++. Я думаю, что более простое рабочее решение было бы более подходящим, даже если оно не так чисто и эффективно. –

+0

@ AnthonyD. Ну, мы не можем отлаживать их код с момента его незавершенности. Это лучшее, что я им дам, если они не отправят mcve. – YSC

+0

Спасибо за ответ! Я понимаю, что вектор векторов дорог и что метод, который вы предлагаете, проще и в чтении, и в скорости, но вы объявляете размер вашей матрицы в начале int main(). Я не знаю, сколько строк будет включено в матрицу, я просто сейчас, когда будут 3 столбца –