Чтение данных из CSV-файла в массив - PullRequest
0 голосов
/ 13 марта 2020

У меня есть CSV-файл, из которого я хочу, чтобы значения были сохранены в трехмерном массиве Cl[x][y][z] в C ++.

Текущий файл, следующий за форматом 2D-массива.

29  26  20  18  
29  25  23  21  
31  28  25  23
33  30  28  25  

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

В настоящее время у меня проблемы с чтением значений из файла CSV и преобразованием их в 3D-массив в C ++.

Это текущий код, который у меня есть:

unsigned short int widthX = wX;
unsigned short int widthY = wY;
unsigned short int widthZ = wZ;
unsigned short int x, y, z;
float clvDefault = 0.0;

float *** Cl = new float**[widthZ];
for (i=0; i<widthZ; i++) 
{
    Cl[i] = new float*[widthY];
    for (j=0; j<widthY; j++) 
    {
        Cl[i][j] = new float[widthX];
    }
}

std::ifstream clvIn;
std::string clvFileName = "File_read.csv";
clvIn.open(clvFileName.c_str());
if(clvIn.fail())
{
    // something bad happened when opening the file
}
std::string filejunk;
char delim;
std::getline(clvIn, filejunk);
int clvX, clvY, clvZ;
float clvValue;

for (z = 0; z < widthZ; z++)
{
    for (y = 0; y < widthY; y++)
    {
        for (x = 0; x < widthX; x++)
        {
            Cl[z][y][x] = clvDefault;
        }
    }
}


while(clvIn >> clvY >> delim >> clvX >> delim >> clvValue)
{
    Cl[0][clvY][clvX] = clvValue;
}

for(y = 0; y < widthY; y++)
{
    for(x = 0; x < widthX; x++)
    {
        clvIn >> Cl[0][y][x] >> delim;
    }

for (z = 1; z < widthZ; z++)
{
    for (y = 0; y < widthY; y++)
    {
        for (x = 0; x < widthX; x++)
        {
            Cl[z][y][x] = Cl[0][y][x];
        }
    }
}

Когда я запускаю код, каждый элемент массива имеет присвоенное мною значение clvDefault, а значения из файла csv не читаются.

Похоже, что l oop пропускается во время бега. Будем благодарны за любые предложения о том, как исправить эту проблему.

1 Ответ

0 голосов
/ 13 марта 2020

В вашей программе много, много ошибок. Позвольте мне перечислить наиболее важные:

  • Использование необработанных указателей для собственной памяти. Никогда не делайте этого в C ++ (если вообще используйте std::unique_ptr)
  • Не используйте new в C ++ для выделения памяти (используйте std::make_unique)
  • Если вы выделяете память с помощью new, тогда вы должны delete потом
  • Лучше всего: использовать контейнер из стандартной библиотеки, в этом случае std::vector
  • Всегда инициализировать все переменные
  • Всегда проверяйте результат файловых операций, таких как открытие или >>
  • Обработка ошибок
  • Использование ++v вместо v++
  • Определение переменных, когда они вам нужны. Держите их в прицеле. Предотвращение загрязнения пространства имен
  • Если вы хотите писать код C ++, используйте элементы языка C ++, а не C
  • Попробуйте создать код с использованием современных элементов языка C ++

Итак. Я исправил ваш код, чтобы он работал, читает ваш файл примера и отображает результат. Я удалил основные ошибки. Пожалуйста, смотрите:

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

float*** get3dArry(unsigned short widthX, unsigned short widthY, unsigned short widthZ) {
    unsigned short int i, j, x, y, z;
    float clvDefault = 0.0;

    float*** Cl = new float** [widthZ];
    for (i = 0; i < widthZ; i++)
    {
        Cl[i] = new float* [widthY];
        for (j = 0; j < widthY; j++)
        {
            Cl[i][j] = new float[widthX];
        }
    }

    std::ifstream clvIn;
    std::string clvFileName = "r:\\File_read.csv";
    clvIn.open(clvFileName.c_str());
    if (clvIn.fail())
    {
        std::cerr << "\n*** Error: Could not open input file\n";
    }
    else {
        std::string filejunk, line;
        char delim;
        //std::getline(clvIn, filejunk);
        int clvX, clvY, clvZ;
        float clvValue;

        for (z = 0; z < widthZ; z++)
        {
            for (y = 0; y < widthY; y++)
            {
                for (x = 0; x < widthX; x++)
                {
                    Cl[z][y][x] = clvDefault;
                }
            }
        }

        for (y = 0; (y < widthY) && std::getline(clvIn, line); ++y) {

            std::istringstream iss{ line };
            for (x = 0; (x < widthY) && (iss >> Cl[0][y][x]); ++x)
                ;
        }

        for (z = 0; z < widthZ; z++)
        {
            for (y = 0; y < widthY; y++)
            {
                for (x = 0; x < widthX; x++)
                {
                    Cl[z][y][x] = Cl[0][y][x];
                }
            }
        }
    }
    return Cl;
}

int main() {
    float*** a3d = get3dArry(4, 4, 3);

    for (int z = 0; z < 3; ++z) {
        std::cout << "\n";
        for (int y = 0; y < 4; ++y) {
            for (int x = 0; x < 4; ++x) {
                std::cout << a3d[z][y][x] << "\t";
            }
            std::cout << "\n";
            delete[] a3d[z][y];
        }
        delete[] a3d[z];
    }
    delete[] a3d;

    return 0;
}

Однако. Я не рекомендовал бы использовать это. Качество очень плохое. Он подвержен ошибкам и каким-то образом все еще заполняет C -программу.

Пожалуйста, посмотрите часть, где я читаю файл CSV. Конечно, нет необходимости во внешней библиотеке. Я часто слышу такие бессмысленные рекомендации для ультра простых файлов CSV. Итак, нет библиотеки. Пример из приведенного выше кода:

for (y = 0; (y < widthY) && std::getline(clvIn, line); ++y) {
    std::istringstream iss{ line };
    for (x = 0; (x < widthY) && (iss >> Cl[0][y][x]); ++x)
        ;
}

Никто не может убедить меня, что мне нужна библиотека, для того, что я могу сделать с 3 простыми строками кода.

Если вы хотите узнать, затем я покажу вам также «более современное» решение C ++:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <iterator>

// Make reading datatypes easier
using DataType = float;
using Matrix1dX = std::vector<DataType>;
using Matrix2dYX = std::vector<Matrix1dX>;
using Matrix3dZYX = std::vector<Matrix2dYX>;

// This is the number of z values for the 3rd dimension. Whatever you want
constexpr size_t NumberOfDimensionZ = 3U;

int main() {

    // Open input csv file, and check, if open operation worked
    if (std::ifstream clvIn("r:\\File_read.csv"); clvIn) {

        // Define 2d array and initialize all values with 0.0;
        Matrix2dYX myx{};

        // Read all lines of the file and split values
        for (std::string line{}; std::getline(clvIn, line); ) {

            // Convert just read string to a std::istringstream
            std::istringstream iss{ line };

            // Add the new values to the 2d array. Iterate over all values in one line
            // then create a 1d vector inplace and add this line values to our 2d matrix
            myx.emplace_back(Matrix1dX(std::istream_iterator<DataType>(iss), {}));
        }
        // Define a 3d matrix, with a given size and having each z-value be the data from the csv file
        Matrix3dZYX mzyx(NumberOfDimensionZ, myx);


        // Some debug output
        // Show result to user
        for (const Matrix2dYX& m2 : mzyx) {
            std::cout << "\n";
            for (const Matrix1dX& m1 : m2) {
                for (const DataType& d : m1) std::cout << d << "\t";
                std::cout << "\n";
            }
        }
    }
    else {
        std::cerr << "\n*** Error: Could not open input file\n";
    }
    return 0;
}

Обратите внимание, что вы можете написать элегантный, очень элегантный и компактный код на C ++.

Для чтения файла и создания 3d вектор, мне не нужно l oop.

Пожалуйста, прочитайте и попытайтесь понять. Пожалуйста, Google unknwon языковых конструкций. Если не понимаешь, то спроси.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...