C++ 将一串数字解析为整数向量的最快方法

C++ 将一串数字解析为整数向量的最快方法,c++,boost,vector,stl,C++,Boost,Vector,Stl,我想知道把一串数字解析成整数向量的最快方法是什么。我的情况是,我将有数百万行数据,格式如下: >Header-name ID1 1 1 12 ID2 3 6 234 . . . >Header-name ID1 1 1 12 ID2 3 6 234 . . . 我想放弃“headername”字段(或者稍后使用它进行排序),然后忽略ID字段,然后将剩余的三个int放入向量中。 我意识到我可以使用boostsplit,然

我想知道把一串数字解析成整数向量的最快方法是什么。我的情况是,我将有数百万行数据,格式如下:

>Header-name
ID1    1    1   12
ID2    3    6   234
.
.
.
>Header-name
ID1    1    1   12
ID2    3    6   234
.
.
.
我想放弃“headername”字段(或者稍后使用它进行排序),然后忽略ID字段,然后将剩余的三个int放入向量中。 我意识到我可以使用boostsplit,然后在两个for循环中使用词法转换,用逻辑忽略某些数据,但我不确定这是否能给我提供最快的解决方案。我看过boost spirit,但我真的不知道如何使用它。Boost或STL都可以。

您必须使用Boost吗? 我已经使用这个函数一段时间了。我相信我是从加速C++中得到的,并且已经使用它了。您的分隔符似乎是一个选项卡或多个空格。如果传递分隔符a“”,它可能会工作。我认为这将取决于实际情况

std::vector<std::string> split( const std::string& line, const std::string& del )
{
        std::vector<std::string> ret;
        size_t i = 0;

        while ( i != line.size() ) {

                while ( ( i != line.size() ) && ( line.substr(i, 1) == del ) ) {
                        ++i;
                }

                size_t j = i;

                while ( ( j != line.size() ) && ( line.substr(j, 1) != del ) ) {
                        ++j;
                }

                if ( i != j ) {
                        ret.push_back( line.substr( i, j - i ) );
                        i = j;
                }
        }

        return ret;
}
std::vector split(常量std::string&line,常量std::string&del)
{
std::载体ret;
尺寸i=0;
而(i!=line.size()){
而((i!=line.size())&&(line.substr(i,1)==del)){
++一,;
}
尺寸j=i;
而((j!=line.size())&&(line.substr(j,1)!=del)){
++j;
}
如果(i!=j){
向后推(第1行,第j-1行);
i=j;
}
}
返回ret;
}
您可以通过以下方式获得每一行:

int main() {
    std::string line;
    std::vector<std::string> lines; 
    while ( std::getline( std::cin, line ) ) {
        lines.push_back( line );
    }

    for ( auto it = lines.begin(); it != lines.end(); it++ ) {
        std::vector<string> vec = split( (*it) );
        // Do something
    }
}
intmain(){
std::字符串行;
std::矢量线;
while(std::getline(std::cin,line)){
线。推回(线);
}
for(auto it=lines.begin();it!=lines.end();it++){
std::vector vec=拆分((*it));
//做点什么
}
}
您可以通过快速修改使其返回std::vector。 使用atoi(myString.c_str())将每个字符串设为int 此外,您还需要签入以跳过标题。应该是琐碎的


请注意,我没有编译上面的内容。;)

您只能使用以下内容,而不是我使用的字符串数组。您将从文件中获取字符串

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

int main() 
{
    std::string s[] = { "ID1    1    1   12", "ID2    3    6   234" };
    std::vector<int> v;

    for ( const std::string &t : s )
    {
        std::istringstream is( t );
        std::string tmp;

        is >> tmp;

        v.insert( v.end(), std::istream_iterator<int>( is ), 
                           std::istream_iterator<int>() );
    }                         

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    return 0;
}
对于标题,您可以检查tmp是否是标题,如果是,您将跳过此记录

这是一个简化的版本

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

int main() 
{
    std::string s[] = 
    { 
        "ID1    1    1   12", 
        ">Header-name", 
        "ID2    3    6   234" 
    };

    std::vector<int> v;

    for ( const std::string &t : s )
    {
        std::istringstream is( t );
        std::string tmp;

        is >> tmp;

        if ( tmp[0] == '>' ) continue;

        v.insert( v.end(), std::istream_iterator<int>( is ), 
                           std::istream_iterator<int>() );
    }                         

    for ( int x : v ) std::cout << x << ' ';
    std::cout << std::endl;

    return 0;
}
#包括
#包括
#包括
#包括
#包括
int main()
{
std::字符串s[]=
{ 
“ID112”,
“>标题名称”,
“ID2 3 6 234”
};
std::向量v;
for(const std::string&t:s)
{
std::istringstream为(t);
std::字符串tmp;
is>>tmp;
如果(tmp[0]=='>')继续;
v、 插入(v.end(),std::istream_迭代器(is),
std::istreamu迭代器();
}                         

对于(intx:v)std::cout这个特定的问题,如果您想要最快的速度,我建议您一次手动解析1个字符。Boost Spirit可能会紧随其后,为您节省大量难看的代码


一次手动解析一个字符是高速的关键,即使像atoi和strtol这样经过优化的转换器也必须处理许多不同的数字表示,而您的示例似乎暗示您只对纯无符号整数感兴趣(scanf,operator与往常一样,对于像这样令人愉快的未明确说明的问题,除了展示“一种方法”来做“一件事”之外,没有什么别的了。在这种情况下,我使用了Boost Spirit(因为您提到了它):

解析到扁平容器中 解析到嵌套容器中 当然,如果您希望每一行有单独的向量(不要期望效率),那么您可以简单地替换typedef:

using Container = std::list<std::vector<int> >; // or any other nested container

// to make printing work without further change:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
    os << "[";
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
    return os << "]";
}

你可以在这里阅读以获得灵感。我想这是一个很好的答案,但是,当我编译时,出现了一些错误:/usr/include/boost/spirit/home/support/algorithm/any_if.hpp:204:72:[跳过5个实例化上下文]&&&/usr/include/boost/spirit/home/support/container.hpp:110:12:错误:“int”不是类、结构或联合类型&&&/usr/include/boost/spirit/home/qi/operator/sequence_base.hpp:86:13:[跳过4个实例化上下文]&&&/usr/include/boost/spirit/home/qi/operator/kleene.hpp:68:17:错误:在“struct boost::spirit::traits::container_value”中没有名为“type”的类型我正在使用boost1.46,这会导致错误吗?很可能是。我正在使用boost 1_55
#include <iostream>
#include <sstream>
#include <vector>
#include <string>

std::vector<unsigned> parse(std::istream &is)
{
    bool skipField = true;
    char c;
    unsigned value = 0;
    std::vector<unsigned> result;
    while (is.get(c))
    {
        if (('\t' == c) || ('\n' == c))
        {
            if (!skipField)
            {
                result.push_back(value);
            }
            skipField = ('\n' == c);
            value = 0;
        }
        else if (!skipField)
        {
            value *= 10;
            value += (c - '0');
        }
    }
    return result;
}

int main()
{
    const std::string data = ">Header-name\nID1\t1\t1\t12\nID2\t3\t6\t234\n";
    std::istringstream is(data);
    const std::vector<unsigned> v = parse(is);
    for (unsigned u: v)
    {
        std::cerr << u << std::endl;
    }
}
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/adapted.hpp>
#include <map>

std::string const input(
    ">Header - name1\n"
    "ID1    1    1   12\n"
    "ID2    3    6   234\n"
    ">Header - name2\n"
    "ID3    3    3   14\n"
    "ID4    5    8   345\n"
);

using Header    = std::string;
using Container = std::vector<int>;
using Data      = std::map<Header, Container>;

int main()
{
    namespace qi = boost::spirit::qi;

    auto f(input.begin()), l(input.end());

    Data data;
    bool ok = qi::phrase_parse(f, l,
        *(
            '>' >> qi::raw[*(qi::char_ - qi::eol)] >> qi::eol
           >> *(!qi::char_('>') >> qi::omit[qi::lexeme[+qi::graph]] >> *qi::int_ >> qi::eol)
        ), qi::blank, data);

    if (ok)
    {
        std::cout << "Parse success\n";
        for (auto const& entry : data)
        {
            std::cout << "Integers read with header '" << entry.first << "':\n";
            for (auto i : entry.second)
                std::cout << i << " ";
            std::cout << "\n";
        }
    }
    else
    {
        std::cout << "Parse failed\n";
    }

    if (f != l)
        std::cout << "Remaining input: '" << std::string(f, l) << "'\n";
}
Parse success
Integers read with header 'Header - name1':
1 1 12 3 6 234
Integers read with header 'Header - name2':
3 3 14 5 8 345
using Container = std::list<std::vector<int> >; // or any other nested container

// to make printing work without further change:
std::ostream& operator<<(std::ostream& os, std::vector<int> const& v)
{
    os << "[";
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
    return os << "]";
}
Parse success
Integers read with header 'Header - name1':
[1 1 12 ] [3 6 234 ]
Integers read with header 'Header - name2':
[3 3 14 ] [5 8 345 ]