我整个星期都在努力让我的一个项目启动并运行。我需要从气象数据库中读取10,000行CSV文件并输出某些字段并进行一些演示(Max blah blah)。
我打算使用自制模板向量来设计它,不允许访问STL库。 因为我刚刚学习,这已经过了几个星期,我认为我已经为自己复杂了,现在我不知道如何进步。 这里的主要问题是我对如何阅读结构并解析信息以仅读取我需要的信息然后将数据转换为模板向量的困惑。
无论如何,不用多说,这是我的源代码:
#include <iostream>
#include <fstream>
#include "Date.h"
#include "Time.h"
#include "Vector.h"
typedef struct {
Date d;
Time t;
float speed;
} WindLogType;
int main()
{
Vector<WindLogType> windlog;
std::string temp;
std::ifstream inputFile("MetData-31-3.csv");
int timeIndex, windSpeedIndex;
//18 Elements per line
//Need the elements at index 0 & 10
while(!inputFile.eof())
{
getline(inputFile, WindLogType.d,' ');
getline(inputFile, WindLogType.t,',');
for(int i = 0; i < 9; i++)
{
getline(inputFile, temp, ',');
}
getline(inputFile, WindLogType.speed);
windlog.push_back(WindLogType);
}
return 0;
}
Vector.h
#ifndef VECTOR_H
#define VECTOR_H
template <class elemType>
class Vector
{
public:
bool isEmpty() const;
bool isFull() const;
int getLength() const;
int getMaxSize() const;
void sort();
// T* WindLogType;
Vector(int nMaxSize = 64); //Default constructor, array size of 64.
Vector(const Vector&); //Copy constructor
~Vector(); //Destructor
void push_back(int);
int operator[](int);
int at(int i);
private:
int maxSize, length;
elemType* anArray;
void alloc_new();
};
template <class elemType>
bool Vector<elemType>::isEmpty() const
{
return (length == 0);
}
template <class elemType>
bool Vector<elemType>::isFull() const
{
return (length == maxSize);
}
template <class elemType>
int Vector<elemType>::getLength() const
{
return length;
}
template <class elemType>
int Vector<elemType>::getMaxSize() const
{
return maxSize;
}
//Constructor that takes the max size of vector
template <class elemType>
Vector<elemType>::Vector(int nMaxSize)
{
maxSize = nMaxSize;
length = 0;
anArray = new elemType[maxSize];
}
//Destructor
template <class elemType>
Vector<elemType>::~Vector()
{
delete[] anArray;
}
//Sort function
template <class elemType>
void Vector<elemType>::sort()
{
int i, j;
int min;
elemType temp;
for(i = 0; i < length; i++)
{
min = i;
for(j = i+1; j<length; ++j)
{
if(anArray[j] < anArray[min])
min = j;
}
temp = anArray[i];
anArray[i] = anArray[min];
anArray[min] = temp;
}
}
//Check if vector is full, if not add the item to the vector
template <class elemType>
void Vector<elemType>::push_back(int i)
{
if(length+1 > maxSize)
alloc_new();
anArray[length]=i;
length++;
}
template <class elemType>
int Vector<elemType>::operator[](int i)
{
return anArray[i];
}
//Return the vector at position 'i'
template <class elemType>
int Vector<elemType>::at(int i)
{
if(i < length)
return anArray[i];
throw 10;
}
//If the vector is about to get full, create a new temporary
//vector of double size and copy the contents across.
template <class elemType>
void Vector<elemType>::alloc_new()
{
maxSize = length*2;
int* tmp=new int[maxSize];
for(int i = 0; i < length; i++)
tmp[i]= anArray[i];
delete[] anArray;
anArray = tmp;
}
/**
//Copy Constructor, takes a reference to a vector and copies
//the values across to a new vector.
Vector::Vector(const Vector& v)
{
maxSize= v.maxSize;
length = v.length;
anArray = new int[maxSize];
for(int i=0; i<v.length; i++)
{
anArray[i] = v.anArray[i];
}
}**/
#endif
矢量类中有些东西是完全没必要的,它们只是来自一些练习。
以下是CSV文件的示例:
WAST,DP,Dta,Dts,EV,QFE,QFF,QNH,RF,RH,S,SR,ST1,ST2,ST3,ST4,Sx,T
31/03/2016 9:00,14.6,175,17,0,1013.4,1016.9,1017,0,68.2,6,512,22.7,24.1,25.5,26.1,8,20.74
31/03/2016 9:10,14.6,194,22,0.1,1013.4,1016.9,1017,0,67.2,5,565,22.7,24.1,25.5,26.1,8,20.97
31/03/2016 9:20,14.8,198,30,0.1,1013.4,1016.9,1017,0,68.2,5,574,22.7,24,25.5,26.1,8,20.92
31/03/2016 9:30,15.1,215,27,0,1013.4,1016.8,1017,0,66.6,5,623,22.6,24,25.5,26.1,8,21.63
我需要WAST列和S列中的元素,因为WAST包含日期而S包含windspeed。
我绝不希望别人给我解决方案,我需要了解我将如何阅读并使用struct&amp; amp解析这些数据。模板矢量。 本身没有真正的“错误”,我只是缺乏对下一步的基本理解。
任何帮助将不胜感激! 三江源
答案 0 :(得分:2)
一种简单有效的方法是每列有一个向量,也就是面向列的存储。面向列的存储最大限度地减少了空间需求,并允许您轻松应用线性代数算法(包括SIMD优化),而无需选择单个结构成员(如行向导存储的情况)。
然后,您可以使用fscanf
解析每一行,将每个值分解为一个单独的变量。然后push_back
将变量放入相应的列中。
由于fscanf
无法解析日期,您需要将日期字符串解压缩到char[64]
,然后将其解析为struct tm
,然后转换为time_t
以上假设您了解CSV的布局和列的类型。
的伪代码:
vector<time_t> timestamps;
vector<double> wind_speeds;
for(;;) {
// Parse the CSV line into variables.
char date_str[64 + 1];
double wind_speed;
fscanf(file, "%64[^,], ..., %lf,...", date_str, ..., &wind_speed, ...);
time_t timestamp = parse_date(date_str);
// Store the parsed variables into the vectors.
timestamps.push_back(timestamp);
wind_speed.push_back(wind_speed);
}
double average_wind_speed = std::accumulate(wind_speeds.begin(), wind_speeds.end(), 0.) / wind_speeds.size();
答案 1 :(得分:0)
.csv文件是表的表示,由“,”(逗号)分隔以更改单元格和“;” (半列)为行尾。
编辑:在案件中;不起作用,通常的“\ n”工作。以下算法可以很容易地应用“\ n”事实上,没有必要创建一个复杂的程序..只要if和while就足够了。这是一个关于如何继续的想法,我希望它可以帮助你理解一个方法,因为它是你要求的。
1- Read every character (store it in a char) and add it to a string (the string += the char).
1.1- If the character is a ",", increase a counter and then you compare the string to the value desired (Here WAST).
1.1.2- If the string equales the desired value, save the counter in an integer (It allows knowing the position of the column you want.)
1.1.2- If not, continue until the end of the line ";" (which means in your case the desired column does not exist) or until you have a match (your string == "WAST")
注意:您可以使用不同的计数器进行操作,以便您知道WAST位置,S位置等。
然后:
Initialise a new counter
2- Compare the new counter to the saved value in 1.1.2.
2.1.1- If the values match, store the char contents in a string until you have a new coma.
2.1.2- If not, read every char until you find a new coma. Then increase your counter and restart from 2.
3- Continue to read the characters until you find a semi-column ";", and restart at step 2, until you finish to read the file.
总结一下,在这种情况下,第一步是读取每个列的名称,直到找到你想要的那个或到达行尾。由于counter1,存储它的位置(注意到“,”(comas))。 读取所有其他行并将字符串存储在所需的列位置(通过“,”(comas)注意到),使用counter1与新计数器进行比较。
它可能不是迄今为止最强大的算法,但它的工作原理很容易理解。
我试图避免在C中写入它,以便您可以在不看编程解决方案的情况下理解这些步骤。我希望它适合你。