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
....

ファイルが異なれば名前付き列の数も異なり、各列の値の型は float、int、および string の間で異なります。

指定された列のデータを適切なタイプのコンテナーに入れる列readColsの名前を送信する関数を作成したいと考えています (たとえば、列tokenと列が必要な場合があります)。rank

私の問題は、ファイルの解析ではなく、さまざまなタイプを含む可変数のコンテナーを返すことです。たとえば、tokenおよび列をおよびコンテナーにそれぞれrank入れたいとします。ここでの問題は、代わりに (ベクトルに格納された) 列が必要になる可能性があり、考えられるすべての型の組み合わせに対して異なる関数を記述したくないということです。(コンテナのタイプは私には関係ありません。s のみを使用する必要がある場合は問題ありません。各コンテナに異なるタイプが含まれていることが重要です。)vector<string>vector<int>epsreadColsvector

おそらく、さまざまな種類のコンテナーを保持するために、さまざまな型を保持するコンテナーが必要になるでしょう。Boost.Variantが私が望む解決策のように見えますが、パーサーに各列をどの型にするかを伝える方法がわかりません (型名のリストのようなものを作成できますか? などvoid readCols(string filename, vector<variant<various types of vector>> &data, vector<string> colNames, vector<typename> convertTo))。同様に、Boost.Mpl.Vectorは問題を解決するかもしれませんが、ここでも、readCols各列がどのようにキャストされるかを知る方法がよくわかりません。

少なくとも 2 つの回避策が考えられます。

  1. 任意のコンテナーに読み込むテンプレート化された関数を使用して、各列を個別に読み取ります (container::value_type関数が解析方法を認識できるようにします)。私はこの解決策を好みません。なぜなら、ファイルが時々大きくなる (数百万行) ため、ファイルを複数回解析すると余分に数分かかるからです (計算に 30 分ほどかかるプログラムでは、実行時間の無視できる割合ではありません。プログラムは何度も走ります)。
  2. すべての列を文字列のコンテナーに読み取り、解析コンテキストではなく呼び出しコンテキストで再キャストします。std::transformandboost::lexical_castまたは s/tを使用して 1 行で変換できると思うので、これはそれほど悪くはありません。2n行の肥大化を避けることができれば、すばらしい ( n= 列の数、通常は 2 または 3、コンテナーを宣言してから変換するための列ごとに 2 行)。

2 番目の回避策は、完全で一般的な解決策よりもはるかに少ない労力で済む可能性があります。もしそうなら、私は知りたいです。2 番目の回避策の方が効率的かもしれないと想像しますが、現時点では主に使いやすさに関心があります。ジェネリックreadCols関数を 1 つ記述してそれで完了できるなら、それが私の好みです。

4

2 に答える 2

1

物事が複雑になりすぎると、問題を小さな部分に分割します。そこで提案です。

コンマまたはその他の区切り記号で区切られた値をファイルから読み取ることができる CSV リーダー クラスを記述します。クラスは一度に 1 行を読み取り、その行を std::string フィールドに分割します。フィールドにアクセスするには、getString、getInt、getDouble などの関数を実装して (列名またはインデックスで) フィールドにアクセスし、それらを適切な型に変換します。したがって、リーダーは明確に定義された処理を行い、限られた数のプリミティブ型を扱います。

次に、CSV リーダーを利用するリーダー関数 (またはクラス) を実装します。これらのリーダー関数は、列の特定の型と、それらの値をどこに置くか (スカラー、コンテナーなど) を認識しています。

于 2012-05-01T21:35:07.810 に答える
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);

(おそらく十分に明確ですが、タイプに応じて必要な列名をリストします。)

これが回避策よりも多かれ少なかれ問題であるかどうかは、見る人の目にかかっています。

于 2012-05-02T16:09:58.430 に答える