用于在C ++中读取CSV文件的数据结构是什么?

时间:2018-02-14 17:53:03

标签: c++ csv join hash hashtable

我的任务是使用程序参数中提供的表(.txt文件)实现散列连接算法。

表格文件可能如下所示:

c1:int,c2:int,c3:string,c4:long
1,1,asd,11
2,3,asdqwe,11

标题行,包含列的名称和列的类型,然后是由","分隔的行。 列数和列类型是可变的。

因此应该存储列名和类型,我必须将它们存储在2D数组或矩阵中。

我必须读取类型并为指定类型的列创建一个容器。 我还必须将所有列存储在异构数组或结构中。

我不知道C ++ 11下面的任何STL容器是异质的。

如何确定列的类型,从其类型创建容器并以异构方式存储所有列数组?

我的努力:

 class Table {
public:
    struct Column {
        std::string name;
        std::string type;

        Column(std::string name, std::string type) : name(name), type(type) {}
    };

    //enum for switch-case
    static enum typeValue {
        INT,
        STRING,
        LONG,
        CHAR,
        DOUBLE,
        SHORT
    };


private:
    std::string filePath;
    std::ifstream file;
    std::vector<Column> columns;
    int rowNumber;
    std::vector<std::array> tableData;

public:
    Table(std::string filePath) {
        this->filePath = filePath;
        rowNumber = 0;
        open();
        loadTableData();


    }


    bool open() {

        file.open(filePath);
        std::string line;
        std::string delimiter = ",";
        size_t pos = 0;
        std::string token;
        getline(file, line);
        while ((pos = line.find(delimiter)) != std::string::npos) {     //parse the columns
            token = line.substr(0, pos);
            size_t posT = 0;
            posT = token.find(":");
            columns.push_back(Column(token.substr(0, posT), token.substr(posT + delimiter.length())));
            line.erase(0, pos + delimiter.length());
        }
        size_t posT = 0;
        posT = line.find(":");
        columns.push_back(Column(line.substr(0, posT), line.substr(posT + delimiter.length())));

        while (std::getline(file, line))    //count the rows
            ++rowNumber;

        for (int i = 0; i < columns.size(); ++i) {

            switch (hashIt(columns[i].type)) {
                case INT:
                    std::vector<int> *tempI = new std::vector<int>();
                    tableData[i] = tempI;
                    break;
                case STRING:
                    std::vector<std::string> *tempS = new std::vector<std::string>();
                    tableData[i] = tempS;
                    break;
                case LONG:
                    std::vector<long> *tempL = new std::vector<long>();
                    tableData[i] = tempL;
                    break;
                case CHAR:
                    std::vector<char> *tempC = new std::vector<char>();
                    tableData[i] = tempC;
                    break;
                case DOUBLE:
                    std::vector<double> *tempD = new std::vector<double>();
                    tableData[i] = tempD;
                    break;
                case SHORT:
                    std::vector<short> *tempSh = new std::vector<short>();
                    tableData[i] = tempSh;
                    break;
                default:
                    std::cerr << "Error: Unsupported column type.";
            }


        }

        //file.close();

        std::cout << "Table " << filePath << " has " << columns.size() << " columns." << std::endl;

        return true;


    }

    bool loadTableData() {
        file.seekg(0, file.beg);
        std::string line;
        getline(file, line); //discarding the column headers

        while (std::getline(file, line)) {
            ++rowNumber;        //count the rows

            for (int i = 0; i < columns.size(); ++i) {

                std::string delimiter = ",";
                size_t pos = line.find(delimiter);
                std::string token = line.substr(0, pos);
                tableData[i].push_back(token);


            }
        }

    }

    template<typename T>

    T **createColumnData(int colNum) {
        T *data = new T[rowNumber]();
        tableData.insert(colNum, data);
    }


    typeValue hashIt(std::string const &inString) {
        if (inString == "int") return INT;
        if (inString == "string") return STRING;
        if (inString == "long") return LONG;
        if (inString == "char") return CHAR;
        if (inString == "double") return DOUBLE;
        if (inString == "short") return SHORT;
        std::cerr << "Error: Unsupported column type.";


        return NULL;

    }


};

谢谢!

1 个答案:

答案 0 :(得分:0)

IMO,您应该将行建模为结构:

struct Row
{
  int column1;
  int column2;
  std::string name;
  int column3;
};

下一步是重载operator>>以读入结构。

std::istream& operator>>(std::istream& inp, Row& r)
{
  char comma;
  inp >> r.column1;
  inp >> comma;
  inp >> r.column2;
  inp >> comma;
  std::getline(inp, r.name, ',');
  inp >> r.column3;
  inp.ignore(100000, '\n');
  return inp;
}

然后你可以阅读记录:

std::vector<Row> database;
Row r;
while (input_file >> r)
{
  database.push_back(r);
}

也许你的下一步是创建索引表。这样可以更快地搜索您的数据库:

std::map<int, int> index_by_column1;
std::map<std::string, int> index_by_name;

该对的第二个值是相关记录的数据库的索引。

查找包含name&#34; Fred&#34;:

的记录
std::map<std::string, int>::const_iterator iter;
iter = index_by_name.find("Fred");
Record r;
if (iter != index_by_name.end())
{
  int database_index = (*iter).second;
  r = database[database_index];
}

您可以使用将索引返回到数据库的哈希表,而不是使用std::map