在多维数组中对.csv排序

时间:2019-06-06 13:36:38

标签: c++ multidimensional-array vector read.csv

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

...

好吧,实际上,这个文件变得非常大。您可以解释行=纬度,列=经度,因此每个块都是按小时测量的坐标图。这些块通常具有row [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 ++是该项目的必然选择...

Tüdelüü, jtotheakob

3 个答案:

答案 0 :(得分:0)

通常,您应该首先考虑数据和数据使用情况。在这里,您可以沿纬度,经度和时间将3D 浮点值(可以是NaN)访问。

如果您可以接受简单(整数)索引,则C ++中的标准方法将是原始数组Anystd::array。经验法则则说:如果在编译时数组知道大小(或者如果要在全局数组上进行操作,则为std::vector),那么就可以使用向量。如果不确定std::array是您的主力军。

因此,您可能会以std:vector结尾。如果一切都是静态的,则可以使用std::vector<std::vector<std::vector<double>>> data,您将以几乎相同的方式进行访问。当心数组是否很大,如果在函数(包括main)中声明它,大多数编译器都会感到窒息,但它可能是一个编译单元中的全局变量(C语言,但在C ++中仍然有效)。

因此,逐行读取文件,并在容器中输入值。如果使用静态定义的数组,只需在每个位置分配新值,如果使用向量,则可以使用data[timeindex][latindex][longindex]动态添加新元素。

对于我来说,这与您当前的代码相差太远了。

静态(C-ish)版本可能包含:

double data[NTIMES][NLATS][NLONGS]

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

push_back

此代码将成功处理NaN并将其转换为特殊的非数字值,但不会检查每行的字段数。为此,请读取#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; } 对其进行解析。

答案 1 :(得分:0)

谢谢,我试图将两个版本都转移到我的代码中,但是我无法使其运行。 猜猜我的编码技巧很差,无法看到其他人显而易见的东西。您可以命名我可能需要的其他库吗? 对于std::isspace,我确实需要#include <cctype>,上面没有在我的代码中提及的其他遗漏之处?

您还能解释if (std::isspace(c) || (c == ',')) std::cin.get();的工作方式吗?据我了解,它将检查c(输入字段是?)是否为空格,如果是,则由于||,正确的术语会自动变为“ true”?那会导致什么后果?

最后,在我们到达指定的数组[time] [lat] [long]后,if (! std::cin) break用于停止循环吗?

无论如何,感谢您的回复。我真的很感激,现在我有了一个定义循环的想法。

答案 2 :(得分:0)

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

但是,我对如何组织此类操作有了一个想法,很可能会将其转移到我的新任务中。

您可以立即关闭此主题;)

欢呼

jtothekaob