c ++在std :: vector中存储逗号分隔的最快方法是啥
Posted
技术标签:
【中文标题】c ++在std :: vector中存储逗号分隔的最快方法是啥【英文标题】:c++ what is the fastest way of storing comma separated int in std::vectorc ++在std :: vector中存储逗号分隔的最快方法是什么 【发布时间】:2011-07-19 04:47:29 【问题描述】:我有一个逗号分隔的整数,我想将它们存储在std::vector<int>
中。目前我正在手动执行此操作。有没有实现上述功能的内置函数?
编辑:
我很着急,忘记提供完整的细节
实际上,我有包含 CSv 的字符串(确切地说是 Unicode 字符串),例如“1,2,3,4,5”
现在我想将它们存储在std::vector<int>
中,所以在上述情况下,我的向量将有五个元素推入其中。目前我正在手动执行此操作,但速度很慢,而且该代码有很多混乱
【问题讨论】:
放一些代码来演示你的确切问题' 您是否在std::vector
中存储整数和逗号?
逗号分隔列表的来源是什么?流?一个字符串?您目前使用的方法是什么?
@iammilind 请参阅我的问题的“编辑”部分中的信息
@Donotalo 请参阅我的问题“编辑”部分中的信息
【参考方案1】:
这可能不是最有效的方法,但这里有一种使用 TR1 正则表达式功能的方法(我在此示例中也使用 C++0x lambda 语法,但显然也可以不使用它):
#include <iostream>
#include <algorithm>
#include <vector>
#include <regex>
#include <iterator>
#include <cstdlib>
std::vector<int> GetList(const std::wstring &input)
std::vector<int> result;
std::wsregex_iterator::regex_type rex(L"(\\d+)(,|$)");
std::wsregex_iterator it(input.begin(), input.end(), rex);
std::transform(it, std::wsregex_iterator(), std::back_inserter(result),
[] (const std::wsregex_iterator::value_type &m)
return std::wcstol(m[1].str().c_str(), nullptr, 10); );
return result;
【讨论】:
我完全忘记了正则表达式库。 +1 证明我错了;)。 这太可爱了。我真的需要探索boost,从那以后我仍然被困在STL中。 @Sharath K Shetty:这没有使用 boost,正则表达式已添加到 STL。 :) 糟糕,没错。正则表达式现在是 C++0x 的一部分。我已经过时了:-(【参考方案2】:为了简单起见,您可以完全在 STL 中执行此操作(易于阅读,不需要复杂的库),这对于编码来说会很快,但在执行速度方面并不是最快的(尽管您可以稍微调整一下,比如在向量中预先保留空间:
std::vector<int> GetValues(std::wstring s, wchar_t delim)
std::vector<int> v;
std::wstring i;
std::wstringstream ss(s);
while(std::getline(ss,i,delim))
std::wstringstream c(i);
int x;
c >> x;
v.push_back(x);
return v;
(无转发(&&
)或 atoi 以保持代码可移植性)。
【讨论】:
如果数据是干净的,这将有效。1 ghghg, 2 fjfjfjf, 3 djdjdjd, 4
怎么样?您的代码将毫无怨言地阅读此内容。您需要在读取值 x 后测试该行上没有其他内容(除了空格)。【参考方案3】:
遗憾的是,STL 不允许您在分隔符上拆分字符串。不过,您可以使用 boost 来执行此操作:(需要最新的 C++ 编译器,例如 MSVC 2010 或 GCC 4.5)
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
int main(int argc, char** argv)
string input = "1,2,3,4";
vector<string> strs;
boost::split(strs, input, boost::is_any_of(","));
vector<int> result;
transform(
strs.begin(), strs.end(), back_inserter(result),
[](const string& s) -> int return boost::lexical_cast<int>(s);
);
for (auto i = result.begin(); i != result.end(); ++i)
cout << *i << endl;
【讨论】:
如果你打算为此使用 Boost,你不妨使用带有 Escaped List Separator 的 Boost Tokenizer:boost.org/doc/libs/1_47_0/libs/tokenizer/… 这可能不是最好的增强用法。您实际上是在对输入进行两次迭代。一次将输入拆分为字符串向量,然后第二次将字符串转换为数字。如果你使用boost::tokenizer,你可以一次性达到同样的效果。 感谢您的建议,确实非常相关。我之前没用过boost:tokenizer
,我再仔细看看。【参考方案4】:
快速而肮脏的选择是使用 C 字符串库 strtok() 函数和 atoi():
void Split(char * string, std::vector<int>& intVec)
char * pNext = strtok(string, ",");
while (pNext != NULL)
intVec.push_back(atoi(pNext));
pNext = strtok(NULL, ",");
根据需要插入您自己的输入数据验证。
见:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
以及宽字符串版本:http://msdn.microsoft.com/en-us/library/2c8d19sb%28v=vs.71%29.aspxhttp://msdn.microsoft.com/en-us/library/aa273408%28v=vs.60%29.aspx
编辑:
请注意,strtok()
将修改您的原始字符串,因此如果需要,请传递一个副本。
【讨论】:
如果目标是运行时速度,那么我想这会更快。请注意,strtok 仅适用于单线程环境。由于代码可能会在初始化期间运行,我想这很好。 上述@Necrolis 的问题:输入 1 jjfjfjf, 2 fjfjfj, 3 gjgjgjg, 4 被解析为好像垃圾不存在。您可以使用boost::lexical_cast<int>()
而不是使用atoi()
,这将转换并验证输入只是一个数字。
strtok 是那些“邪恶”函数之一,其结果可能与您的预期不同。 "a,b,c" 加载三个元素。 "a,,b" 只加载两个元素。使用该功能时请记住这一点。【参考方案5】:
试试这个:
它将读取由任何字符(您选择)分隔的任何类型(可以用 >> 读取)。
注意:读取对象后,对象和分隔符之间只能有空格。因此,对于ObjectSepReader<std::string, ','>
之类的内容,它将读取一个由“,”分隔的单词列表。
这使得使用我们的标准算法变得简单:
#include <vector>
#include <sstream>
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
std::stringstream data("1,2,3,4,5,6,7,8,9");
std::vector<int> vdata;
// Read the data from a stream
std::copy(std::istream_iterator<ObjectSepReader<int, ','> >(data),
std::istream_iterator<ObjectSepReader<int, ','> >(),
std::back_inserter(vdata)
);
// Copy data to output for testing
std::copy(vdata.begin(), vdata.end(), std::ostream_iterator<int>(std::cout," "));
使它工作的秘密课程。
template<typename T,char S>
struct ObjectSepReader
T value;
operator T const&() const return value;
;
template<typename T,char S>
std::istream& operator>>(std::istream& stream, ObjectSepReader<T,S>& data)
char terminator;
std::string line;
std::getline(stream, line, S);
std::stringstream linestream(line + ':');
if (!(linestream >> data.value >> terminator) || (linestream.tellg() != line.size()+1) || (terminator != ':'))
stream.setstate(std::ios::badbit);
return stream;
【讨论】:
【参考方案6】:我个人会创建一个结构并让向量包含该结构的实例。 像这样:
struct ExampleStruct
int a;
int b;
int c;
;
vector<ExampleStruct> structVec;
【讨论】:
【参考方案7】:这个怎么样?
#include <string>
#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>
struct PickIntFunc
PickIntFunc(std::vector<int>& vecInt): _vecInt(vecInt),_pBegin(0)
char operator () (const char& aChar)
if(aChar == ',' || aChar == 0)
_vecInt.push_back(atoi(std::string(_pBegin,&aChar).c_str()));
_pBegin = 0;
else
if(_pBegin == 0)
_pBegin = &aChar;
return aChar;
const char* _pBegin;
std::vector<int>& _vecInt;
;
int _tmain(int argc, _TCHAR* argv[])
std::vector<int> vecInt;
char intStr[] = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20";
std::for_each(intStr,intStr+sizeof(intStr),PickIntFunc(vecInt));
// Now test it
std::for_each(vecInt.begin(),vecInt.end(), [] (int i) std::cout << i << std::endl;);
return 0;
【讨论】:
以上是关于c ++在std :: vector中存储逗号分隔的最快方法是啥的主要内容,如果未能解决你的问题,请参考以下文章
当C ++将元素从函数的返回值存储到std :: vector时出现意外的结果
存储在向量中的 C++ std::function 不起作用