我想知道将一串数字解析为整数向量的最快方法。我的情况是,我将拥有数百万行数据,格式如下:
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
>Header-name
ID1 1 1 12
ID2 3 6 234
.
.
.
我想丢弃" Header-name"字段(或者可以在以后使用它进行排序),然后忽略ID字段,然后将剩余的三个整数放入向量中。 我意识到我可以使用boost split然后在一些for循环中使用词法强制转换逻辑来忽略某些数据,但是我不确定这是否会给我最快的解决方案。我看过提升精神,但我真的不懂如何使用它。 Boost或STL都可以。
答案 0 :(得分:1)
你必须使用助推吗? 我已经使用了这个功能一段时间了。我相信我是从Accelerated C ++中得到的,并且从那时起就开始使用它。您的分隔符似乎是一个制表符,或多个空格。如果您通过分隔符“”它可能会起作用。我认为这取决于实际存在的内容。
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;
}
你可以用这个来获得每一行:
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
}
}
你可以通过快速修改来返回std :: vector。 使用atoi(myString.c_str())使每个字符串成为一个int 此外,您还需要签入以跳过标题。应该是微不足道的。
请注意,我没有编译上面的内容。 ;)
答案 1 :(得分:1)
关于这个具体问题,如果你想要最快,我建议一次手动解析1个字符。提升精神可能会紧随其后,为你节省很多丑陋的代码。
一次手动解析一个char是高速的关键,因为即使是优化的转换器(如atoi和strtol)也必须处理许多不同的数字表示,而您的示例似乎暗示您只对纯无符号整数感兴趣。格式化的IO(scanf,operator&lt;&lt;等)非常慢。将线条读入中间字符串可能会产生可见的成本。
您的问题很简单,只需手动解析,假设标题行不包含任何&#39; \ t&#39; (并假设没有任何IO或格式错误):
#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;
}
}
答案 2 :(得分:1)
与往常一样,如果有这样令人愉快的问题,那么除了展示“一种方式”做“一件事”之外别无其他。在这种情况下,我使用了Boost Spirit(因为你提到过):
#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
当然,如果你想为每一行提供单独的向量(不要期望效率),那么你可以简单地替换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 << "]";
}
打印
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 ]
答案 3 :(得分:0)
您可以使用类似以下内容而不是我使用的字符串数组,您将从文件中获取字符串
#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;
}
输出
1 1 12 3 6 234
至于标题,那么你可以检查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;
}
输出与上面相同。