Текстовый файл C++ со столбцами в 2D-вектор

У меня есть текстовый файл со значениями, и я хочу поместить их в 2D-вектор.

Я могу сделать это с массивами, но я не знаю, как это сделать с векторами.

Размер вектора должен быть как vector2D[nColumns][nLines], который я не знаю заранее. Самое большее, что я могу иметь в текстовом файле, это количество столбцов, но не количество строк. Количество столбцов может быть разным, от одного файла .txt к другому.

.txt пример:

189.53  -1.6700 58.550  33.780  58.867
190.13  -3.4700 56.970  42.190  75.546
190.73  -1.3000 62.360  34.640  56.456
191.33  -1.7600 54.770  35.250  65.470
191.93  -8.7500 58.410  33.900  63.505

с массивами я делаю так:

//------ Declares Array for values ------//
const int nCol = countCols; // read from file
float values[nCol][nLin]; 

// Fill Array with '-1'
for (int c = 0; c < nCol; c++) {
    for (int l = 0; l < nLin; l++) {
        values[c][l] = -1;
    }
}

// reads file to end of *file*, not line 
while (!inFile.eof()) {
    for (int y = 0; y < nLin; y++) {
        for (int i = 0; i < nCol; i++) {
            inFile >> values[i][y];
        }
        i = 0;  
    }
}

person JMG    schedule 09.12.2013    source источник
comment
while (!inFile.eof()) неправильно. Прекрати это!   -  person Lightness Races in Orbit    schedule 09.12.2013
comment
@LightnessRacesinOrbit Что следует использовать вместо этого?   -  person JMG    schedule 09.12.2013


Ответы (2)


Мое предложение:

const int nCol = countCols; // read from file
std::vector<std::vector<float>> values;  // your entire data-set of values

std::vector<float> line(nCol, -1.0);  // create one line of nCol size and fill with -1

// reads file to end of *file*, not line 
bool done = false;
while (!done) 
{
    for (int i = 0; !done && i < nCol; i++) 
    {
        done = !(inFile >> line[i]);
    }
    values.push_back(line);  
}

Теперь ваш набор данных имеет:

values.size() // number of lines

и также может быть адресован с помощью нотации массива (помимо использования итераторов):

float v = values[i][j];

Примечание: этот код не учитывает тот факт, что в последней строке может быть меньше значений данных nCol, и поэтому конец вектора строки будет содержать неправильные значения в конце файла. Вы можете добавить код, чтобы очистить конец вектора линии, когда done становится ложным, прежде чем вы вставите его в значения.

person DNT    schedule 09.12.2013
comment
Я пробовал, но все еще с некоторыми предупреждениями и ошибками на графиках, результат не такой, как я ожидал. Как сделать так: .txt values ​​столбец 1 -> vector[0][j]; столбец значений .txt 2 -> vector[1][j]; ... ? - person JMG; 09.12.2013
comment
Вектор значений представляет собой набор строк ваших данных. Ваша таблица в (0,0) имеет значения [0][0], а третий элемент данных в строке 2 (56,970) имеет значения [1][2]. Крайний левый индекс вектора значений — это номер строки, отсчитываемый от нуля, а самый правый — номер столбца (снова отсчитываемый от нуля). Это представление является основным по строкам (ссылка: en.wikipedia.org/wiki/Row-major_order). Вот как ваш исходный код считывал значения из файла. Под «значения столбца 1 -> вектор [0] [j]» вы подразумеваете, что теперь хотите, чтобы ваши данные были в формате столбца? - person DNT; 09.12.2013
comment
Я хотел бы получить значения из .txt из первого столбца в значениях [0] [i], из третьего столбца в значениях [2] [i]... Таким образом, значение (56,970) должно быть в значениях [ 2][1] - person JMG; 09.12.2013
comment
Я также мог бы продолжать использовать массивы, но мне нужно уменьшить начальный размер. Является ли это возможным? Кроме того, можно ли узнать количество строк в одном файле? - person JMG; 09.12.2013
comment
Хорошо, это похоже на формат столбцов. std::vector сам по себе требует мало памяти по сравнению с содержащимися в нем данными. Иерархия начинается с класса _Container_base (без элементов данных), затем класса _Vector_val (содержит ссылку на объект распределителя), затем шаблона векторного класса, который содержит 3 указателя (первый, последний, конец). Упрощая, всего 4 указателя/ссылки, которые в 64-битной системе составляют 8x4 = 32 байта на экземпляр векторного класса. В большинстве случаев это очень небольшие накладные расходы по сравнению с содержащимися данными. - person DNT; 09.12.2013
comment
продолжение: Что касается строк файла, пожалуйста, прочитайте мой ответ под кодом. Это значения.size(). Что касается основного порядка столбцов, он полезен только в том случае, если вам нужно выполнить операции со всем столбцом, поменять местами столбцы и т. д., и в этом случае вам нужно будет определить другой вектор‹vector‹float›› col_major, вектор‹float› column(values.size()), затем перебираем значения следующим образом: for (int c=0; c‹nCol; c++) { for (int r=0; r‹values.size(); r++) { column[ г] = значения[г][с]; } col_major.push_back(столбец); } [может кто-нибудь показать мне, как отформатировать это в комментарии?] - person DNT; 09.12.2013

Вместо использования

float values[nCol][nLin]; 

использовать

std::vector<std::vector<float>> v;

Вы должны #include<vector> для этого.

Теперь вам не нужно беспокоиться о размере.

Добавление элементов так же просто, как

std::vector<float> f; f.push_back(7.5); v.push_back(f);

Также не используйте .eof() для потоков, потому что он не устанавливает его до тех пор, пока не будет достигнут конец, и поэтому он попытается прочитать конец файла.

while(!inFile.eof()) 

Должно быть

while (inFile >> values[i][y]) // returns true as long as it reads in data to values[x][y]

ПРИМЕЧАНИЕ. Вместо vector вы также можете использовать std::array, что, по-видимому, лучше всего после нарезанного хлеба.

person Tony The Lion    schedule 09.12.2013
comment
Если количество столбцов известно и постоянно во всем наборе данных, то этот метод можно оптимизировать, определив один вектор вне цикла, изменив его размер до количества столбцов, а затем повторно установив для него значения. в цикле и в конце каждой итерации помещая его в результирующий вектор. - person DNT; 09.12.2013
comment
Однако я должен отметить, что std::vector немного медленнее, чем обычный массив C. Если OP нужна максимальная производительность, ему следует использовать std::vector с осторожностью. - person eraxillan; 09.12.2013
comment
@DNT, потому что использование std::arrays слишком распространено - person Shoe; 09.12.2013
comment
@Axilles [нужна цитата]. - person Bartek Banachewicz; 09.12.2013
comment
@BartekBanachewicz Что ты имеешь в виду? я не понимаю. - person eraxillan; 09.12.2013
comment
@JMG вы также можете индексировать вектор, например массив C, с помощью оператора индекса - person Tony The Lion; 09.12.2013
comment
Добавление элементов так же просто, как std::vector‹float› f; f.push_back(7.5); v.push_back(f); Но как я могу сделать это, читая из столбцов текстового файла? Каждый столбец должен быть в каждом векторном измерении. Например: столбец значений 1 -> 1-й вектор; столбец значений 2 -> 2-й вектор; столбец значений 3 -> 3-й вектор; ... - person JMG; 09.12.2013
comment
@Axilles Вашему заявлению нужно больше данных, чтобы подтвердить его. Доступ к элементам вектора — это та же арифметика указателя, что и доступ к элементам массива. Где медленнее? Насколько? Это действительно имеет значение? Почему бы не использовать std::array вместо этого? - person Bartek Banachewicz; 09.12.2013
comment
@Jeffrey std::array является стандартом C++ 2011 года. Он недоступен в старых компиляторах, и поскольку версия компилятора здесь не указана, я предложил использовать std::vector, который поддерживается старыми компиляторами. - person DNT; 09.12.2013
comment
@JMG здесь подразумевается, что вы должны поместить все значения одной строки в std::vector‹float›, а затем поместить их в свой последний std::vector‹std::vector‹float››, прежде чем начинать следующая строка. - person DNT; 09.12.2013
comment
@BartekBanachewicz Я имею в виду перераспределение стоимости блоков памяти. т.е. вектор как динамическая структура может быть медленнее, чем массив C фиксированного размера или std::array. Однако эту проблему можно решить, используя огромные значения в функции reserve функции std::vector. Стоимость создания векторного объекта и вызова его операторов минимальна, согласен. - person eraxillan; 09.12.2013
comment
@Axilles, если возникнет необходимость перераспределить массив C, время перераспределения будет таким же большим, как с вектором, не так ли? Итак, какова реальная прибыль? - person Bartek Banachewicz; 09.12.2013
comment
@BartekBanachewicz Хорошо, теперь я перестану спорить, потому что у меня нет конкретных данных о различиях в производительности между std::vector и массивом C. Я просто хочу предупредить OP, что они существуют: для работы с объектом C++ требуется дополнительный код, не так ли? Таким образом, это должно замедлить выполнение программы до некоторого (небольшого) значения. - person eraxillan; 09.12.2013
comment
@Axilles Код будет удален компилятором при оптимизации, так что нет, здесь нет реальных накладных расходов. - person Bartek Banachewicz; 09.12.2013
comment
@BartekBanachewicz Извините за этот оффтоп, но не могли бы вы назвать хорошие статьи по этому поводу: Код будет удален компилятором при оптимизациях. Я подозреваю, что это будет удалено только ХОРОШИМ компилятором :) - person eraxillan; 09.12.2013
comment
@Axilles Каждый последний компилятор хорош. GNU G++, Clang, MSVS, ICC — все должны иметь дело с такого рода тривиальными оптимизациями. - person Bartek Banachewicz; 09.12.2013
comment
@TonyTheLion Я хочу использовать векторы, потому что таким образом мне не нужно знать количество столбцов или строк. Как мне это сделать, если я не знаю этих чисел: while (inFile ›› values[i][y]) // возвращает true, пока считывает данные в values[x][y]? - person JMG; 09.12.2013