在多维数组中对.csv进行排序

Sort .csv in multidimensional arrays

本文关键字:csv 排序 数组      更新时间:2023-10-16

我正在尝试从.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
...

好的,实际上,这个文件变得非常大。您可以解释行=纬度和列=经度,因此每个块都是每小时测量的坐标图。这些块通常具有行[361]列[720]的大小,时间段可以长达20年(= 24 * 365 * 20块),只是为了让您了解数据大小。

为了构建它,我想扫描.csv并将每个块定义为一个向量 t,我可以通过选择所需的时间步长 t=0,1,2,3 来访问它......

然后,在这个块中,我想转到一条特定的线(即纬度)并将其定义为矢量经度数组。

结果应为时间 Z 处坐标 XY 的指定值。

正如您可能猜到的那样,我的编码经验相当有限,这就是为什么我的实际问题可能非常简单:如何排列我的向量以便能够调用任何随机值?

这是我到目前为止的代码(可惜它不多,因为我不知道如何继续......

#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事物访问。

如果您可以接受简单(整数)索引,则C++中的标准方式是原始数组,std::arraystd::vector。经验法则说:如果在编译时数组(或者std::array如果你想对全局数组进行操作)的大小是可以的,否则使用向量。如果不确定std:vector是你的主力。

所以你可能会以一个std::vector<std::vector<std::vector<double>>> data结尾,你会用它作为data[timeindex][latindex][longindex]。如果一切都是静态的,您可以使用或多或少以相同方式访问的double data[NTIMES][NLATS][NLONGS]。当心数组很大,如果你在函数(包括main)中声明它,大多数编译器都会阻塞,但它可能是在一个编译单元中的全局(C-ish,但在C++中仍然有效)。

因此,逐行读取文件,在容器中输入值。如果使用静态定义的数组,只需将每个新值分配在其位置,如果使用向量,则可以使用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
...
}

使用向量的更动态的版本可能是:

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对其进行解析。

谢谢,我尝试将两个版本都转移到我的代码中,但我无法让它运行。 猜猜我糟糕的编码技能无法看到其他人显而易见的东西。你能说出我可能需要的其他库吗? 对于std::isspace我确实需要#include <cctype>,上面我的代码中没有提到的其他遗漏是什么?

您能解释一下if (std::isspace(c) || (c == ',')) std::cin.get();是如何工作的吗?据我了解,它将检查c(哪个是输入字段?)是否是空格,如果是这样,正确的术语会因为||而自动变为"true"?由此产生什么后果?

最后,if (! std::cin) break用于在我们到达指定的数组[时间][纬度][长]后停止循环?

无论如何,感谢您的回复。我真的很感激它,我现在知道如何定义我的循环。

再次感谢大家的想法。 不幸的是,我无法运行脚本...但是我的任务略有变化,因此不再需要读取非常大的数组。

但是,我已经知道如何构建此类操作,并且很可能会将其转移到我的新任务中。

您现在可以关闭此主题;)

干杯

Jtothekaob