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;

(无转发(&amp;&amp;)或 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&lt;int&gt;() 而不是使用atoi(),这将转换并验证输入只是一个数字。 strtok 是那些“邪恶”函数之一,其结果可能与您的预期不同。 "a,b,c" 加载三个元素。 "a,,b" 只加载两个元素。使用该功能时请记住这一点。【参考方案5】:

试试这个: 它将读取由任何字符(您选择)分隔的任何类型(可以用 >> 读取)。 注意:读取对象后,对象和分隔符之间只能有空格。因此,对于ObjectSepReader&lt;std::string, ','&gt; 之类的内容,它将读取一个由“,”分隔的单词列表。

这使得使用我们的标准算法变得简单:

#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 不起作用

如何分隔列的字符串并将它们存储在向量中[重复]

C / C ++如何将3维数组存储在内存中以及遍历它的最快方法是啥

C读取以逗号分隔的数字文件

将使用 PIMPL 习语的类存储在 std::vector 中