c ++, какой самый быстрый способ хранения запятой, разделенной int в std :: vector - PullRequest
2 голосов
/ 19 июля 2011

У меня целые числа через запятую, и я хочу сохранить их в std::vector<int>.В настоящее время я делаю это вручную.Есть ли встроенная функция, которая выполняла вышеуказанные функции?

Редактировать:

Я спешил и забыл поставить полную информацию На самом деле у меня есть строка (точнее Unicode строка), содержащая CSvнапример, «1,2,3,4,5». Теперь я хочу сохранить их в std::vector<int>, поэтому в приведенном выше случае в мой вектор будет вставлено пять элементов.В настоящее время я делаю это вручную, но это медленно, так как с этим кодом много путаницы

Ответы [ 7 ]

4 голосов
/ 19 июля 2011

Вероятно, это не самый эффективный способ, но вот способ сделать это, используя функциональность регулярного выражения TR1 (в этом примере я также использую лямбда-синтаксис C ++ 0x, но, очевидно, это можно было бы сделать и без этого):

#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;
}
3 голосов
/ 19 июля 2011

Вы можете сделать это, используя чисто 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 для сохранения переносимости кода).

2 голосов
/ 19 июля 2011

Быстрая и грязная опция заключается в использовании функции strtok () из библиотеки строк C и 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

EDIT: Обратите внимание, что strtok() изменит исходную строку, поэтому при необходимости передайте копию.

2 голосов
/ 19 июля 2011

К сожалению, 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;
}
1 голос
/ 19 июля 2011

Попробуйте это:
Он будет читать любой тип (который можно прочитать с помощью >>), разделенный любым символом (который вы выберете).
Примечание. После чтения объекта между объектом и разделителем должно быть только пространство. Таким образом, для таких вещей, как 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;
}
0 голосов
/ 19 июля 2011

Как насчет этого?

#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;
}
0 голосов
/ 19 июля 2011

Лично я бы создал структуру, и вектор содержал бы экземпляры структуры.Вот так:

struct ExampleStruct
{
    int a;
    int b;
    int c;
};
vector<ExampleStruct> structVec;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...