2

我的数据如下所示:

     token            eps  rank # first line names columns
 Intercept   9.362637e+00     1 # later lines hold data
        A1  -2.395553e-01    30
        G1  -3.864725e-01    50
        T1   1.565497e-01    43
....

不同的文件将具有不同数量的命名列,并且每列中的值类型将在浮点数、整数和字符串之间有所不同。

我想编写一个readCols函数,向其发送列名(例如,我可能需要tokenrank列),它将指定列中的数据放入适当类型的容器中。

我的问题不在于解析文件,而在于返回包含不同类型的可变数量的容器。例如,我希望将tokenrank列分别放入vector<string>vector<int>容器中。这里的问题是我可能想要该eps列(存储在向量中),并且我不想readCols为每种可能的类型组合编写不同的函数。(容器的类型对我来说无关紧要。如果我必须只使用vectors,没问题;每个容器包含不同的类型是关键。)

我可能需要一个容纳不同类型的容器来容纳不同类型的容器。看起来Boost.Variant可能是我想要的解决方案,但我不知道如何告诉解析器我希望每列是哪种类型(我可以制作类似类型名列表的东西吗?例如void readCols(string filename, vector<variant<various types of vector>> &data, vector<string> colNames, vector<typename> convertTo))。同样,Boost.Mpl.Vector可能会解决问题,但我还是不太清楚如何判断readCols每列想要如何转换。

我至少可以想到两种解决方法:

  1. 使用读入任何容器的模板化函数分别读取每一列(container::value_type允许函数知道如何解析)。我不喜欢这种解决方案,因为文件有时很大(数百万行),因此多次解析它们会花费额外的几分钟(在计算需要约 30 分钟的程序中,运行时间的百分比可忽略不计;程序将一遍又一遍地跑)。
  2. 将所有列读入字符串容器并在调用上下文而不是解析上下文中重新转换它们。这不会那么糟糕,因为我认为我可以使用std::transformandboost::lexical_cast或 s/t 在一行中进行转换。如果我能避免2n臃肿的行,那就太好了(n=列数,通常为 2 或 3,每列 2 行来声明容器然后转换)。

与完整的通用解决方案相比,第二种解决方法可能需要我付出的努力要少得多;如果是这样,我想知道。我想第二种解决方法甚至可能更有效,但我目前主要关心的是易用性。如果我可以编写一个通用readCols函数并完成它,那就是我更喜欢的。

4

2 回答 2

1

当事情变得太复杂时,我将问题分解成更小的部分。所以这里有一个建议。

编写一个 CSV 阅读器类,它可以从文件中读取逗号或其他分隔符分隔的值。该类一次读取一行并将该行分成 std​​::string 字段。为了访问字段,您需要实现 getString、getInt、getDouble 等函数来访问字段(按列名或索引)并将它们转换为适当的类型。因此,读者做了一个定义明确的事情并处理有限数量的原始类型。

然后实现使用 CSV 阅读器的阅读器功能(或类)。这些读取器函数知道列的特定类型以及将它们的值放在哪里——无论是在标量、容器等中。

于 2012-05-01T21:35:07.810 回答
0

只要返回值的类型是有限的,例如intdoublestd::string,这样的函数就可以完成这项工作:

using namespace std;
void readCols(string fileName, vector<string> stringCols, 
      vector<string> intCols, vector<string> doubleCols, 
      vector<vector<string> > *stringData, 
      vector<vector<int> > *intData, 
      vector<vector<double> > *doubleData);

(可能足够清楚,但是您根据它们的类型列出所需的列名。)

旁观者认为这是否比解决方法更麻烦。

于 2012-05-02T16:09:58.430 回答