读取二维数组在CSV到map++



我是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 <字符串,map><string,>>"使得结果映射是有序的:

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

任何帮助将非常感激!谢谢你!

[EDIT]行和列的数量是预先知道的-不需要计数。我对c++比较陌生(从OPL优化语言迁移过来),对文件操作也不是很熟悉。

由于您正在使用空白作为分隔字符,因此您应该能够使用标准<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;
}

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

如果可以使用任意数量的分隔符,那么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();
}  

最新更新