2014-12-17 2 views
-1

Я ищу помощь в создании динамически расширяющегося массива для импорта данных из CSV-файла. Я не хочу видеть, насколько велик файл и редактировать переменную в исходном коде/приглашать пользователя, я просто хочу, чтобы данные были импортированы, а затем обрабатывались различными способами. Во-первых, мой код as-is:Что такое хороший способ динамического расширения массива для импорта данных?

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

int main() 
{ 

//declare variables and arrays 
long rows = 170260; 
int cols = 5; 
double **rawData = new double*[rows]; //on heap because of size 
for(long pi = 0; pi < rows; ++pi) //create an array of pointers 
{ 
     rawData[pi] = new double[cols]; 
} 
char buff[200]; 
double deltaT; 
double carDeltaV; 
double *carV = new double[rows]; //on heap because of size 

//import raw data 
std::cout << "Importing filedata.csv..."; 

std::ifstream rawInput("filedata.csv"); 

for(long r = 0; r < rows; ++r) 
{ 
     rawInput.getline(buff, 200); 
     std::stringstream ss(buff); 

     for(int c = 0; c < cols; ++c) 
     { 
      ss.getline(buff, 40, ','); 
      rawData[r][c] = atof(buff); 
     } 
} 

std::cout << "Done." << std::endl; 

//create speed matrix 
carV[0] = 0; 

std::cout << std::endl << "Creating speed matrix..."; 

for (long i = 1; i < rows; ++i) 
{ 

    deltaT = rawData[i][0] - rawData[i-1][0]; 
    carDeltaV = rawData[i-1][3] * deltaT; 
    carV[i] = carDeltaV + carV[i-1]; 
} 

std::cout << "Done." << std::endl; 

//write data to csv file 
std::cout << std::endl << "Writing data to file..."; 

std::ofstream outputData; 
outputData.open("outputdata.csv"); 

for(long r = 0; r < rows; ++r) 
{ 
     outputData << rawData[r][0] << "," << rawData[r][3]/.00981 << ","; 
     outputData << carV[r] << std::endl; 
} 

outputData.close(); 
std::cout << "Done." << std::endl; 

//delete pointers 
std::cout << std::endl << "Clearing memory..."; 

for(long pj = 0; pj < rows; ++pj) 
{ 
     delete [] rawData[pj]; 
} 
delete [] rawData; 
delete [] carV; 

std::cout << "Done." << std::endl; 

std::cin.get(); 
return 0; 

} 

Примечание: количество колонок всегда будет 5. Строки неизвестны. Пример того, что я буду импортировать можно увидеть ниже:

0.001098633,0.011430004,0.002829004,-0.004371409,0.00162947 
0.001220703,0.00606778,0.001273052,0.003497127,0.002359922 
0.001342773,0.003104446,-0.000848701,0.,-0.008119254 

Существует больше к этому, но это должно быть достаточно, чтобы понять, что я пытаюсь сделать. Я немного почитал на векторах, но концепция вектора-векторов немного сбивает меня с толку, и я попытался реализовать ее без успеха. Кроме того, я читал, что дека может быть тем, что я ищу? У меня нет опыта с ними, и мне кажется, что это может быть излишним для моего приложения, поскольку я только добавляю в одном направлении массив данных.

Отказ от ответственности: Я в значительной степени новичок на C++, поэтому, если есть какие-либо концепции, которые, по вашему мнению, будут выше моего уровня мастерства, пожалуйста, дайте мне знать, чтобы я мог прочитать об этом.

Любые советы?

Редактировать: По запросу, вот как я пытался сделать это с помощью векторов.

std::vector<double> rawDataRow; 
std::vector< std::vector<double> > rawDataMatrix; 

//import raw data loop 
std::ifstream rawInput("test.csv"); 

for(int i = 1; i > 0;) { 
      rawInput.getline(buff, 200); 
      std::stringstream ss(buff); 

      for(int c = 0; c < cols; ++c) { 
        ss.getline(buff, 40, ','); 
        value = atof(buff); 
        rawDataRow.push_back(value); 

        std::cout << rawDataRow[0] << std::endl; 
      } 
      timeDiff = timeAfter - timeBefore; 
      timeBefore = timeAfter; 
      timeAfter = rawDataRow[0]; 

      rawDataMatrix.push_back(rawDataRow); 
} 

где «i» будет установлено равным 0 на уровне eof.

+8

Используйте 'зОго :: вектора ' с подходящим типом 'T', чтобы удерживать элементы и использовать' vector.push_back (значение) 'для добавления каждой записи. Класс позаботится о росте по мере необходимости. –

+0

Вы можете показать свой код в векторе? –

+0

Вы используете только первый и четвертый столбцы? Если это так, вы можете сэкономить усилия, не преобразовывая строку, чтобы удвоить остальные три значения в строке. –

ответ

0

Резюмируя вопросы, возникшие в ходе обсуждения:

Вы не можете иметь вектор массивов: вот, там Correct way to work with vector of arrays Вы можете иметь вектор указателей на массивы. Однако в этот момент я бы не стал возиться со всей обработкой памяти.

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

std::vector< std::vector<double> > rawDataMatrix; 

//import raw data loop 
std::ifstream rawInput("test.csv"); 

for(int i = 1; i > 0;) { 
     std::vector<double> rawDataRow; 
     rawInput.getline(buff, 200); 
     std::stringstream ss(buff); 

     // do the rest 
} 
0

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

Чтобы удобно иметь дело с вводом строки, то первая вещь, которую я определил бы это простой манипулятор, который будет игнорировать запятую:

std::istream& comma(std::istream& in) { 
    if ((in >> std::ws).peek() == ',') { 
     in.ignore(); // the happy case: just skip over the comma 
    } 
    else if (!in.peek() == std::char_traits<char>::eof()) { 
     in.setstate(std::ios_base::failbit); // unhappy: not the end and not a comma 
    } 
    return in; 
} 

с этим на месте, это довольно легко читать строки и разделить их в клетки:

std::vector<std::vector<double>> result; 
for (std::string line; std::getline(in, line);) { 
    std::istringstream lin(line); 
    std::vector<double> row; 
    for (double d; d >> lin >> comma;) { 
     row.push_back(d); 
    } 
    if (!lin.eof()) { 
     in.setstate(std::ios_base::failbit); 
    } 
    std::result.push_back(row); 
} 
if (!in.eof()) { 
    std::cout << "there was an input error\n"; 
} 
else { 
    // result contains the result of reading... 
} 

Я не проверял код и я предполагаю, что есть где-то опечатки, но общий подход должен просто работать ...

+0

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

0

Во-первых, вы должны разделить программу на три части:

  1. Чтение данных из входного файла
  2. обработки данных
  3. Запись данных в выходной файл

Ваш главный программа должна в основном выглядеть так:

int main() { 
    vector<InputRecord> data = read_from_csv("filedata.csv"); 
    vector<double> speeds = compute_speeds(data); 
    write_to_csv("result.csv", data, speeds); 
    return 0; 
} 

Теперь вам нужно определить, что такое InputRecord. Вы сказали, что это массив из 5 парных, но это не лучшее описание. Это должно быть больше, как это:

struct InputRecord { 
    double timestamp; 
    double field2; 
    double field3; 
    double location; 
    double field5; 
}; 

Используя эту структуру данных, вы можете написать data[0].timestamp вместо data[0][0], что означает, что вам не нужны комментарии больше.

Вот полный код, который я написал для этой задачи. Это похоже на то, что вам нужно, и должно быть хорошим в качестве отправной точки. Обратите внимание, что этот код вообще не использует явное управление памятью.

#include <cstdio> 
#include <cstdlib> 
#include <fstream> 
#include <iostream> 
#include <string> 
#include <vector> 

using std::string; 
using std::vector; 

struct InputRecord { 
    double timestamp; 
    double field2; 
    double field3; 
    double location; 
    double field5; 
}; 

vector<InputRecord> read_from_csv(const char *filename) { 
    std::ifstream in(filename); 
    vector<InputRecord> data; 

    if (!in.is_open()) { 
    throw std::ios_base::failure(string() 
     + "cannot open input file \"" + filename + "\"."); 
    } 

    string line; 
    while (std::getline(in, line)) { 
    InputRecord rec; 
    char end_of_line; 
    if (std::sscanf(line.c_str(), "%lf,%lf,%lf,%lf,%lf%c", 
     &rec.timestamp, &rec.field2, &rec.field3, 
     &rec.location, &rec.field5, &end_of_line) != 5) { 
     throw std::ios_base::failure(string() 
      + "input file \"" + filename + "\" " 
      + "contains invalid data: \"" + line + "\""); 
    } 
    data.push_back(rec); 
    } 
    if (in.bad()) { 
    throw std::ios_base::failure(string() + "error while reading data"); 
    } 
    return data; 
} 

vector<double> calculate_speeds(const vector<InputRecord> &data) { 
    vector<double> speeds; 

    speeds.push_back(0.0); 
    for (std::size_t i = 1; i < data.size(); i++) { 
    double delta_t = data[i].timestamp - data[i - 1].timestamp; 
    double delta_s = data[i].location - data[i - 1].location; 
    speeds.push_back(delta_s/delta_t); 
    } 
    return speeds; 
} 

void write_to_csv(const char *filename, const vector<InputRecord> &data, 
    const vector<double> &speeds) { 
    std::ofstream out(filename); 

    if (!out.is_open()) { 
    throw std::ios_base::failure(string() 
     + "cannot open output file \"" + filename + "\"."); 
    } 
    for (std::size_t i = 0; i < data.size(); i++) { 
    out << data[i].timestamp << "," << speeds[i] << "\n"; 
    } 
    if (out.bad()) { 
    throw std::ios_base::failure(string() + "error while writing data"); 
    } 
} 

int main() { 
    vector<InputRecord> data = read_from_csv("in.csv"); 
    vector<double> speeds = calculate_speeds(data); 
    write_to_csv("out.csv", data, speeds); 
    return 0; 
} 
+0

Благодарим вас за подробный ответ. Я попробую это сегодня. – snickodonnell

+0

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

Смежные вопросы