从tsv中读取100k+行的特定行数据,仅使用标准库

Read specific row of data from tsv with 100k+ lines, using standard libraries only

本文关键字:标准 数据 tsv 读取 100k+      更新时间:2023-10-16

Edit3最终解决方案如下。

我有以下结构的数据文件(它是模拟分析的设计点矩阵):

+----------+----------------------+-----------------+----------+----------+----------+-----------+-------------+
| ConfigID | k_StrategiesPerAgent | K_StrategySpace | l_Lambda | m_Memory | n_Agents | p_crowded |   s_Seed    |
+----------+----------------------+-----------------+----------+----------+----------+-----------+-------------+
|      0.0 |                  0.0 |             0.0 |      0.5 |     12.0 |     10.0 |       0.2 | 353756906.0 |
|      1.0 |                  0.0 |             0.2 |      0.5 |     12.0 |     10.0 |       0.2 | 923055597.0 |
|      2.0 |                  0.0 |             0.4 |      0.5 |     12.0 |     10.0 |       0.2 | 616881203.0 |
+----------+----------------------+-----------------+----------+----------+----------+-----------+-------------+

文件"DPM。是制表符分隔的,不包含空格或自由行等,即:

ConfigID    k_StrategiesPerAgent    K_StrategySpace l_Lambda    m_Memory    n_Agents    p_crowded   s_Seed
0.0 0.0 0.0 0.5 12.0    10.0    0.2 353756906.0
1.0 0.0 0.2 0.5 12.0    10.0    0.2 923055597.0
2.0 0.0 0.4 0.5 12.0    10.0    0.2 616881203.0

它可能包含超过100k行和大量列。第一列是一个唯一的标识符(Integer, [0,…]),我想使用它来访问与它相关的参数值。一般来说,"ConfigID"的编号应该是重要的。我事先不知道列数

我正在寻找一个函数,该函数将在头读入字符串向量和相应的数据,对应于键,进入双向量(相同的排序)。这应该在没有任何特殊库的情况下完成,因为我不知道如何链接它们…此外,我会欣赏一个非常简单的结构,没有类/模板等工作。就像

vector<string> Labels; //Hold the parameter labels
vector<double> Parameters; //Hold the parameter values
bool readPars(char * FilePath, int ConfigID); //load the label and value
                                            //return [false] on error, else [true]

小后续:然后我想通过循环访问向量中的数据,将值从我用于模拟(模拟开发实验室)的"语言"传递给一些宏。因此,我还想将字符串"转换"为字符。这可以通过添加"。c_str()"到字符串来完成,对吗?例句:

for (int i=0;i<Labels.size();i++){
  const char * lab = Labels[i].c_str();
  double par = Parameters[i];
  LSD_MACRO(lab,par)//do something
}

ConfigID也是标签[]和参数[]的一部分是可以的

鉴于我缺乏编程经验,我过去的"解决"方法是编写一个python脚本,硬编码一个包含所有数据的数组,然后通过#include包含…但是这种方法也有局限性。

多谢!弗雷德里克


解决方案:遵循Jonathan Mee的答案并加载所有内容。

using namespace std;
#include <fstream>
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
#include <iostream>
#include <limits>
int main()
{ 
  const char * DPM_File = "DPM.tsv";
  cout << DPM_File <<  endl; 
  ifstream  fileP(DPM_File); //Read File in tsv format, with header-line
  //read the header
  string label;
  getline(fileP, label, 'n'); 
  //create a string vector with the header
  istringstream gccNeedsThisOnASeperateLine{ label };                                   
  const vector<string> Labels{ istream_iterator<string>{ gccNeedsThisOnASeperateLine }, istream_iterator<string>{} };         
  //Read the remainer and parse it to a 2d vector of doubles
  vector<vector<double>> Parameters;
  do {
        vector<double> input(Labels.size());
        for(int i = 0; i < input.size(); i++){ 
        fileP >> input[i];
      }
      if(!fileP.fail()) //control for empty line at end of file
         Parameters.push_back(input);     
    } while(fileP.ignore(numeric_limits<streamsize>::max(), 'n'));
  //Test:
  for (int i=0;i<Labels.size();i++){    
    cout << Labels[i] << "t" << Parameters[0][i]  << endl;
  }
  cout << endl;
  for (int i=0;i<Labels.size();i++){    
    cout << Labels[i] << "t" << Parameters[5][i]  << endl;
  }
  cout << endl;
  int sssize = Parameters.size();
  cout << "The sssize is" << sssize << endl;
  for (int i=0;i<Labels.size();i++){    
    cout << Labels[i] << "t" << Parameters[sssize-1][i]  << endl;
  }
  cout << endl;
  return 0;
}

让我们来谈谈你的数据结构:

  1. 标签必须与包含double的结构分开保存,否则您将最终获得n-相同标签的副本。我们把标签放在容器vector<string> Labels
  2. 如果你的键列是连续的,从1开始,简单地把你的双子星放在vector<vector<double>> Parameters和索引将作为从零开始的键,如果不是你需要使用map<int, vector<double>> Parameters,因为它更简单,我们将假设数字是连续的,并使用vector<vector<double>> Parameters

如果你已经成功地将文件打开到ifstream fileP,你可以像这样得到你的Labels:

string label;
getline(fileP, label, 'n');   
const vector<string> Labels{ istream_iterator<string>{ istringstream{ label } }, istream_iterator<string>{} };

虽然有更花哨的方法,但我们可以简单地使用嵌套的for -循环来提取vector<vector<double>> Parameters:

while(fileP.ignore(std::numeric_limits<std::streamsize>::max(), 't')) {
    vector<double> input(size(Labels) - 1);
    for(int i = 0; i < size(input) && fileP >> input[i]; ++i);
    Parameters.push_back(input);
}
<<p> 生活例子/kbd>