在C ++中使用indexof函数

时间:2014-05-05 04:21:13

标签: c++ dictionary indexof unordered-map

我的这个问题是基于我之前提出的问题。

Multi level hash/dictionary creation in C++

我有这个结构,我需要使用indexof函数存储在unordered_map中。我正在使用上一个问题中指定的配置文件。我需要将第一行存储为索引,将后续值存储为该索引下的数组。

到目前为止,我已经能够做到这一点。

#include <cstdlib.h>

#include <stdafx.h>
#include <string.h>
#include <stdio.h>
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std::tr1;

#define false 0
#define true 1

int main()
{
    unordered_map <std::string, int> m;
    FILE *f;

    char c[255];
    char * pnt;

    f=fopen("Config.csv","r");
    if(f==NULL)
    return 1;

    while(!feof(f))
    {    
        fgets(c, 255, f);  //go to the next line
        pnt = strtok( c, ",");
        while( pnt!= NULL ) 
        {

            //the code for storing the values goes here.
            pnt = strtok( NULL, "," );
        }
    }
    fclose(f);
    return 0;
}

我的CSV文件看起来像这样----

USN,Name,DOB,Sem,Percentage
111,abc,07/03,3,88
112,cde,18/07,4,77

1 个答案:

答案 0 :(得分:0)

在我看来,正在使用的正确数据结构是std::unordered_map<std::string,std::vector<std::string>>不是 unordered_map<std::string,int>,正如您当前的实现所尝试的那样。这个,因为你想要存储的字段看起来更像字符串;有些根本没有。

第一步是提取字段名称,以便以后可以将它们用作unordered_map键。然后开始提取数据行,将它们标记为字段。接下来,对于每个字段名称,push_back给定CSV行的字段数据。这是一个例子(使用一些C ++ 11结构):

#include <string>
#include <iostream>
#include <vector>
#include <unordered_map>
#include <sstream>

std::vector<std::string> split ( std::string );

int main () {

  // Sample data for a self-contained example.
  std::vector<std::string> raw_data {
    "USN,Name,DOB,Sem,Percentage",
    "111,abc,07/03,3,88",
    "112,cde,18/07,4,77"
  };


  // Ordered container for field names, unordered for field vectors.
  auto field_names = split( raw_data[0] );
  std::unordered_map<std::string,std::vector<std::string>> parsed;


  // Store fields as vector elements within our unordered map.
  for( auto it = std::begin(raw_data) + 1; it != std::end(raw_data); ++it ) {
    auto fields = split( *it );
    auto field_it = std::begin(fields);
    for( auto name_it = std::begin(field_names);
         name_it != std::end(field_names);
         ++name_it,
         ++field_it
    ) {
      parsed[*name_it].push_back(*field_it);
    }
  }


  // Dump our data structure to verify it's correct;
  for( auto fn : field_names ) {
    std::cout << fn << "\t";
  }
  std::cout << "\n";
  for ( size_t ix = 0; ix != parsed[field_names[0]].size(); ++ix ) {
    for( auto fn : field_names ) {
      std::cout << parsed[fn][ix] << "\t";
    }
    std::cout << "\n";
  }
  std::cout << std::endl;


  return 0;
}


std::vector<std::string> split ( std::string instring ) {
  std::vector<std::string> output;
  std::istringstream iss(instring);
  std::string token;
  while( getline( iss, token, ',' ) ) {
    output.push_back(token);
  }
  return output;
}

在我的示例中,我从名为raw_data的向量中包含的输入数据开始。在您的情况下,您从文件中提取数据。因此,我正在处理数据结构的构建,因为我假设文件处理不是您问题的核心部分。您应该能够很容易地从我的示例中调整数据结构的标记化和构建。

另外,我知道你使用的是tr1 :: unordered_map,这可能意味着你没有使用C ++ 11。尽管如此,我的C ++ 11-isms实际上只是利用语法糖,你可以降级到相同的C ++ 03兼容性而不需要太多的工作。

注意,这是一种相对天真的CSV解析方法。它做出的假设可能适用于您的CSV数据,但可能不适用于所有形式的CSV。例如,它不处理字段引用以允许在字段内嵌入逗号。它也不涉及反斜杠转义的逗号,也不涉及许多其他CSV解析挑战。

如果您的数据集的性能不如此解析器可以处理的那么好,那么您应该找到一个完整的CSV解析库而不是摆弄您自己的解析器。 ......至少那些如果我的任务是解析不那么琐碎的CSV形式,我会怎么做。