#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 байта на экземпляр векторного класса. В большинстве случаев это, по сравнению с содержащимися данными, очень небольшие накладные расходы.