2011-07-19 32 views
2

我有一個逗號分隔整數,我想將它們存儲在std::vector<int>。目前我正在手動執行此操作。是否有任何內置函數執行上述功能?什麼是最快的方式存儲逗號分隔詮釋在std :: vector

編輯:含

我在趕時間,忘了把全部細節 其實我有字符串(準確的Unicode字符串)的CSV例如「1,2,3,4,5」 現在,我想將它們存儲在std::vector<int>中,所以在上述情況下,我的向量將有五個元素推入它。目前我正在通過手動執行此操作,但其速度很慢,並且代碼很雜亂

+1

把一些代碼來演示你的確切問題' – iammilind

+1

你是否在'std :: vector'中存儲整數和逗號? – Donotalo

+0

逗號分隔列表的來源是什麼?流?一個字符串?你目前使用的方法是什麼? – Sven

回答

3

爲了簡單起見,您可以純粹在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

這個在數據乾淨的情況下可以使用,那麼'1 ghghg,2 fjfjfjf,3 djdjdjd,4'你的代碼會在沒有抱怨的情況下讀取它,你需要在閱讀值x表示沒有希望ng行(空格除外)。 –

0

就我個人而言,我會創建一個結構並讓該向量包含該結構的實例。 像這樣:

struct ExampleStruct 
{ 
    int a; 
    int b; 
    int c; 
}; 
vector<ExampleStruct> structVec; 
2

可悲的是,STL不允許你對一個分隔符分開的字符串。您可以使用boost做雖然它:(需要近期C++編譯器,如2010 MSVC或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; 
} 
+1

如果您要使用爲此,你可以使用Boost Tokenizer和Escaped List Separator:http://www.boost.org/doc/libs/1_47_0/libs/tokenizer/escaped_list_separator.htm – Ferruccio

+2

這可能不是最好的提升使用率。你實際上迭代了兩次輸入。一旦將輸入分割爲一個字符串矢量,然後再次將字符串轉換爲數字。如果您使用[boost :: tokenizer](http://www.boost.org/doc/libs/1_36_0/libs/tokenizer/tokenizer.htm),則可以在一次傳遞中獲得相同的效果。 –

+0

感謝您的建議,確實非常相關。我之前沒有使用'boost:tokenizer',我會仔細看看。 –

4

它可能不是最有效的方式,但這裏有一個辦法做到這一點使用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; 
} 
+0

我完全忘記了正則表達式庫。 +1證明我錯了;)。 –

+0

這真可愛。我真的需要探索提升,自從我永遠堅持STL。 – Sharath

+0

@Sharath K Shetty:這不是使用boost,正則表達式被添加到STL。 :) – Sven

0

這個怎麼樣?

#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; 
} 
2

的快速和骯髒的方法是使用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.aspx
http://msdn.microsoft.com/en-us/library/aa273408%28v=vs.60%29.aspx

編輯: 注意strtok()會修改你的原始字符串,那麼通行一個副本如果需要的話。

+1

如果目標是運行時速度,那麼我認爲速度更快。小心,strtok只能在單線程環境下工作。由於代碼可能會在初始化過程中運行,所以我猜這樣做很好。 –

+0

Saem問題如上面的@Necrolis:輸入1 jjfjfjf,2 fjfjfj,3 gjgjgjg,4被解析爲垃圾不在那裏,而不是使用'atoi()',你可以使用'boost :: lexical_cast ()'這會轉換並驗證輸入只是一個數字 –

+0

strtok是那些'邪惡'函數之一,其結果可能會與您期望的不同。「a,b,c」加載三個元素。「a ,, b」只加載兩個元素,在使用函數的時候記住這一點 – EvilTeach

1

嘗試這種情況:
它將讀取的任何類型(即可以是用>>分隔)(用你選擇的字符)
注意:讀取對象後,對象和分隔符之間只能有空格。因此對於像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; 
} 
相關問題