将CSV中的二维数组读入Map c ++

时间:2014-07-20 19:07:37

标签: c++ arrays csv cplex

我是CPLEX用户,我需要将CSV文件中的数组数据转换为C ++ 2D Map作为我的优化问题的输入。数据以列的形式显示。也就是说,如果我们考虑3行(AA1,AA2,AA3)和3列(BB1,BB2,BB3)及其各自的值,它们在CSV文件中具有以下格式:

ROW,COL,VALUE
AA1,BB1,0.3
AA2,BB1,0.5
AA1,BB2,0.6
AA1,BB3,0.7
AA2,BB2,0.9
AA3,BB2,0.5
AA3,BB1,0.6
AA2,BB3,0.4
AA3,BB3,0.6

如您所见,数据不按行或列排序。我希望将数据读入格式的二维地图" map<字符串,地图< string,float>> "这样就得到了生成的地图:

ROW,COL,VALUE
AA1,BB1,0.3
AA1,BB2,0.6
AA1,BB3,0.7
AA2,BB1,0.5
AA2,BB2,0.9
AA2,BB3,0.4
AA3,BB1,0.6
AA3,BB2,0.5
AA3,BB3,0.6

任何帮助将不胜感激!谢谢。

[编辑] 行数和列数事先知道 - 无需计算。我对C ++相对较新(从OPL优化语言迁移),我对文件操作不是很熟悉。任何示例代码对我理解程序都非常有帮助。

2 个答案:

答案 0 :(得分:1)

由于您使用空格作为分隔符,因此您应该能够使用标准<ifstream>实现快速实现此功能:

#include <ifstream>
#include <string>
#include <map>
#include <iostream>

int main() {
    // Open file:
    std::ifstream fin("filename.csv"); // Open in text-mode.

    // Opening may fail, always check.
    if (!fin) { 
        std::cout << "Error, could not open file." << std::endl; 
        return -1;
    }

    // Construct your map.
    std::map< std::string, std::map<std::sting, float> > valMap;

    // Read the file and load the data:
    std::string row, column;
    float value;
    while ( fin >> row >> column >> value ) { // Reads three values from file.
          valMap[row][col] = value;  // Adding the values to the map, if the cell is 
                                     // a duplicate: It will be overwritten.
    }

    // Close the file:
    fin.close();

    // Printing out the data like you described:
    for ( auto & columnMap : valMap ) {
        for ( auto cell : columnMap.second ) {
                std::cout << columnMap->first /*First label*/ << " "
                          << cell->first      /*Second label*/ << " "
                          << cell->second     /* Value */ << std::endl;
        }
    }

    return 0;
}

答案 1 :(得分:0)

好的,我会在第二个答案中添加这个,因为这是解决同一问题的完全不同的方法。

如果您可以使用任意数量的不同分隔符,strtok是一个很好的选择。它原本是C,所以你需要让你的手更加肮脏,但这是值得的。

char * strtok ( char * str, const char * delimiters );

采用两个参数,第一个是我们要分析的字符串,第二个是包含我们想要用作分隔符的所有不同字符的字符串。

对于您的特定用例,我会建议以下内容:

#include <cstring>
#include <cstdlib>
#include <string>
#include <fstream>
#include <iostream>

const char * DELIMS = "\t ,"; // Tab, space or comma.
const int MAX_LINE_LENGTH = 1024; // Choose this large enough for your need.
                                  // Or use a dynamic buffer together with 
                                  // std::string and getline(istream, string&).

int main() {
    std::fstream fin("filename.csv");

    // Test for errors

    // Prepare a C-string buffer to be used when reading lines.
    char buffer[MAX_LINE_LENGTH] = {};        

    // Prepare map.
    std::map< std::string, std::map< std::string, float>> valMap;

    // Read one line at a time.
    while ( fin.getline(buffer, MAX_LINE_LENGTH) ) {
          // Extract the three tokens:
          const char * row = strtok( buffer, DELIMS );
          const char * col = strtok( NULL,   DELIMS );
          const char * val = strtok( NULL,   DELIMS );

          // You could do additional errorchecking here, 
          // as for instance checking that there are no more valid tokens, 
          // and that all row, col and val are non-NULL.

          // Insert elements.
          valMap[std::string(row)][std::string(col)] = std::atof(val);
    }      

    // Cleanup
    fin.close();
}