我的数据如下:
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
函数,我发送列的名称(例如,我可能想要token
和rank
列),这些列将把数据放在指定的列中进入适当类型的容器。
我的问题不是解析文件,而是返回包含不同类型的可变数量的容器。例如,我希望token
和rank
列分别放入vector<string>
和vector<int>
容器中。这里的问题是我可能想要eps
列(存储在向量中),并且我不想为每种可能的类型组合编写不同的readCols
函数。 (容器的类型对我来说无关紧要。如果我只需要使用vector
,没问题;每个容器包含不同的类型是关键。)
我可能需要一个容纳不同类型的容器来容纳不同类型的容器。看起来Boost.Variant可能是我想要的解决方案,但我不知道如何告诉解析器我想要每个列的类型(我可以创建类似名称的列表吗?例如{{1} })。同样地,Boost.Mpl.Vector可以解决问题,但我再也无法确定如何告诉void readCols(string filename, vector<variant<various types of vector>> &data, vector<string> colNames, vector<typename> convertTo)
每列想要如何投射。
我至少可以考虑两种解决方法:
readCols
允许函数知道如何解析)。我不喜欢这个解决方案,因为文件偶尔很大(数百万行),因此多次解析它们需要额外的几分钟(在计算需要约30分钟的程序中,运行时间的百分比可以忽略不计;程序将一遍又一遍地跑。)container::value_type
和std::transform
或s / t在一行中进行转换。如果我可以避免boost::lexical_cast
行膨胀,那么(2n
=列数通常为2或3,每列2行以声明容器然后进行转换)。 可能第二种解决方法需要的工作量比完整的通用解决方案要少得多;如果是这样的话,我想知道。我想第二种解决方法甚至可能更有效,但我主要关注的是目前的易用性。如果我可以编写一个通用n
函数并完成它,那就是我更喜欢的。
答案 0 :(得分:1)
当事情变得太复杂时,我将问题分解成更小的部分。所以这是一个建议。
编写一个CSV阅读器类,它可以从文件中读取逗号或其他分隔符分隔值。该类一次读取一行并将该行拆分为std :: string字段。为了访问这些字段,您可以实现访问字段(按列名或索引)的getString,getInt,getDouble等函数,并将它们转换为适当的类型。因此,读者做了一个定义明确的事情,并处理有限数量的原始类型。
然后实现使用CSV阅读器的阅读器功能(或类)。这些读者函数知道列的特定类型以及放置值的位置 - 在标量,容器等中。
答案 1 :(得分:0)
只要返回值的类型有限,例如int
,double
或std::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);
(可能很清楚,但你根据它们的类型列出了你想要的列名。)
这种解决方案是否比解决方案更多或更少是在旁观者的眼中。