我正在尝试从 .csv 文件中读取特定值(即 values@coordinate XY),并努力寻找在该 .csv 中定义多维数组的正确方法。
这是我的 .csv 文件中的表单示例
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
NaN,NaN,1.23,2.34,9.99
1.23,NaN,2.34,3.45,NaN
1.23,NaN,2.34,3.45,NaN
...
好吧,实际上,这个文件变得非常大。您可以解释行=纬度和列=经度,因此每个 block 都是每小时测量的坐标图。这些 block 的大小通常为行[361] 列[720],时间段最长可达 20 年(=24*365*20 个 block ),只是为了让您了解数据大小。
为了构造它,我想到了扫描 .csv 并将每个 block 定义为 vector t,我可以通过选择所需的时间步长 t=0,1,2,3...来访问它
然后,在此 block 中,我想转到特定行(即纬度)并将其定义为 vector longitudeArray。
结果应为坐标 XY 在时间 Z 的指定值。
正如您可能猜到的那样,我的编码经验相当有限,这就是为什么我的实际问题可能非常简单:我如何安排我的 vector 以便能够调用任何随机值?
这是我到目前为止的代码(遗憾的是它不多,因为我不知道如何继续...)
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int longitude, latitude; //Coordinates used to specify desired value
int t; //Each array is associated to a specific time t=0,1,2,3... (corresponds to hourly measured data)
string value;
vector<string> t; //Vector of each block
vector<string> longitudeArray; //Line of array, i.e. latitude
ifstream file("swh.csv"); //Open file
if (!file.is_open()) //Check if file is opened, if not
print "File could..."
{
cout << "File could not open..." << endl;
return 1;
}
while (getline(file, latitude, latitude.empty())) //Scan .csv (vertically) and delimit every time a white line occurs
{
longitudeArray.clear();
stringstream ss(latitude);
while(getline(ss,value,',') //Breaks line into comma delimited fields //Specify line number (i.e. int latitude) here??
{
latitudeArray.push_back(value); //Adds each field to the 1D array //Horizontal vector, i.e. latitude
}
t.push_back(/*BLOCK*/) //Adds each block to a distinct vector t
}
cout << t(longitudeArray[5])[6] << endl; //Output: 5th element of longitudeArray in my 6th block
return 0;
如果您有任何提示,尤其是如果有更好的方法处理大型 .csv 文件,我将不胜感激。
Ps:C++对于这个项目来说是不可避免的...
图德吕, jtotheakob
最佳答案
像往常一样,您应该首先考虑数据和数据使用情况。这里有浮点值(可以是 NaN),应该可以作为 3D thing 沿纬度、经度和时间访问。
如果您可以接受简单的(整数)索引,C++ 中的标准方法就是原始数组,std::array
和 std::vector
.经验法则是:如果大小在编译时已知,数组(或者 std::array
如果你想对全局数组进行操作)就可以了,否则就用 vector 。如果不确定std:vector
是你的主力军。
所以你可能会以 std::vector<std::vector<std::vector<double>>> data
结尾,您将用作 data[timeindex][latindex][longindex]
.如果一切都是静态的,你可以使用 double data[NTIMES][NLATS][NLONGS]
您将或多或少以相同的方式访问。当心数组是否很大,如果您在一个函数(包括 main)中声明它,大多数编译器会阻塞,但它可能是一个编译单元中的全局变量(C-ish 但在 C++ 中仍然有效)。
因此,逐行读取文件,将值输入您的容器。如果您使用静态定义的数组,只需在其位置分配每个新值,如果您使用 vector ,则可以使用 push_back
动态添加新元素。 .
这与您当前的代码相去甚远,我无法向您展示更多琐碎的代码。
静态(C-ish)版本可能包含:
#define NTIMES 24*365*20
#define NLATS 361
#define NLONGS 720
double data[NTIMES][NLATS][NLONGS];
...
int time, lat, long;
for(time=0; time<NTIMES; time++) {
for (lat=0; lat<NLATS; lat++) {
for (long=0; long<NLONGS; long++) {
std::cin >> data[time][lat][long];
for (;;) {
if (! std::cin) break;
char c = std::cin.peek();
if (std::isspace(c) || (c == ',')) std::cin.get();
else break;
}
if (! std::cin) break;
}
if (! std::cin) break;
}
if (! std::cin) break;
}
if (time != NTIMES) {
//Not enough values or read error
...
}
使用 vector 的更动态的版本可能是:
int ntimes = 0;
const int nlats=361; // may be a non compile time values
const int nlongs=720; // dito
vector<vector<vector<double>>> data;
int lat, long;
for(;;) {
data.push_back(vector<vector<double>>);
for(lat=0; lat<nlats; lat++) {
data[ntimes].push_back(vector<double>(nlongs));
for(long=0; long<nlongs; long++) {
std::cin >> data[time][lat][long];
for (;;) {
if (! std::cin) break;
char c = std::cin.peek();
if (std::isspace(c) || (c == ',')) std::cin.get();
else break;
}
if (! std::cin) break;
}
if (! std::cin) break;
}
if (! std::cin) break;
if (lat!=nlats || long!=nlongs) {
//Not enough values or read error
...
}
ntimes += 1;
}
此代码将成功处理 NaN 并将其转换为特殊的非数字 值,但它不会检查每行的字段数。为此,请阅读带有 std::getline
的一行并使用 strstream
解析它。
关于c++ - 在多维数组中对 .csv 进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56478805/