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

#c #arrays #file #ifstream #getline

#c #массивы #вектор #корень

Вопрос:

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

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

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

пример .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;  
    }
}
 

Комментарии:

1. while (!inFile.eof()) это неправильно. Прекрати это!

2. @LightnessRacesinOrbit Что следует использовать вместо этого?

Ответ №1:

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

 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 , что, по-видимому, лучше всего после нарезанного хлеба.

Комментарии:

1. Если количество столбцов известно и постоянно во всем наборе данных, то этот метод можно оптимизировать, определив один вектор вне цикла, изменив его размер на количество столбцов, а затем повторно задавая ему значения в цикле и в конце каждогоитерация, вставляющая его в результирующий вектор.

2. Однако я должен отметить std::vector , что он немного медленнее, чем обычный массив C. Если оператору требуется максимальная производительность, он должен использовать std::vector его с осторожностью.

3. @DNT, потому что использование std::array s слишком распространено

4. @Подмышечные впадины [требуется цитирование].

5. @BartekBanachewicz Что вы имеете в виду? я не понимаю.

Ответ №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 amp;amp; i < nCol; i  ) 
    {
        done = !(inFile >> line[i]);
    }
    values.push_back(line);  
}
 

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

 values.size() // number of lines
 

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

 float v = values[i][j];
 

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

Комментарии:

1. Я пробовал, но все еще с некоторыми предупреждениями и ошибками на графиках, результат не тот, который я ожидал. Как я могу сделать это следующим образом: .txt значения столбца 1 -> вектор [0] [j]; .txt значения столбца 2 -> вектор [1] [j]; … ?

2. Вектор значений представляет собой набор строк из ваших данных. Ваша таблица в (0,0) имеет значения [0] [0], а третий элемент данных в строке 2 (56.970) имеет значения [1] [2]. Крайний левый вектор индекса значений — это номер строки, основанный на нуле, а крайний правый — номер вашего столбца (снова основанный на нуле). Это представление является основным в строке (ссылка: en.wikipedia.org/wiki/Row-major_order ). Вот как ваш исходный код считывал значения из файла. Под ‘значения столбца 1 -> вектор [0] [j]’ вы имеете в виду, что теперь вы хотите, чтобы ваши данные были в формате основного столбца?

3. Я хотел бы иметь значения из файла .txt из первого столбца в значениях [0][i], из 3-го столбца в значениях [2] [i]… Таким образом, значение (56.970) должно быть в значениях [2][1]

4. Я мог бы также продолжать использовать массивы, но мне нужно уменьшить начальный размер. Возможно ли это? Кроме того, можно ли узнать количество строк в одном файле?

5. Хорошо, это похоже на формат основного столбца. Std::vector сам по себе имеет небольшие затраты памяти по сравнению с данными, которые он содержит. Иерархия начинается с класса _Container_base (без элементов данных), затем класса _Vector_val (содержит ссылку на объект распределителя), затем шаблона векторного класса, который содержит 3 указателя (первый, последний, конец). Упрощая, всего 4 указателя / ссылки, которые в 64-битной системе составляют 8×4 = 32 байта на экземпляр векторного класса. В большинстве случаев это, по сравнению с содержащимися данными, очень небольшие накладные расходы.