Что эквивалентно функции join () для QStringList только с использованием STL? [Дубликат]

Вы хотите сделать join . Существует много учебников об этом и различных способах делать это.

19
задан Michael Kristofik 14 February 2012 в 16:14
поделиться

8 ответов

Используйте delimiter.c_str() как разделитель :

copy(x.begin(),x.end(), ostream_iterator<int>(s,delimiter.c_str()));

Таким образом, вы получаете const char*, указывающие на строку, что ostream_operator ожидает от ваш std::string.

19
ответ дан Fanael 15 August 2018 в 14:45
поделиться
  • 1
    +1, но также обратите внимание, что это будет записывать конечный delimiter на выходе. – David Rodríguez - dribeas 14 February 2012 в 15:49
  • 2
    Я не уверен в производительности здесь. A stringstream управляет собственным буфером, поэтому он должен динамически расти. Здесь вы знаете, прежде чем генерировать строку, какой длины она будет, поэтому вы должны зарезервировать буфер перед конкатенацией. – wilhelmtell 14 February 2012 в 15:56
  • 3
    «вы знаете, прежде чем генерировать строку, какую длину она будет». - или, во всяком случае, вы знаете верхнюю границу. Если stringstream увеличивает свой буфер экспоненциально, то я бы не стал беспокоиться о производительности, но я не знаю, так ли это. – Steve Jessop 14 February 2012 в 16:33
int array[ 6 ] = { 1, 2, 3, 4, 5, 6 };
std::vector< int > a( array, array + 6 );
stringstream dataString; 
ostream_iterator<int> output_iterator(dataString, ";"); // here ";" is delimiter 
std::copy(a.begin(), a.end(), output_iterator);
cout<<dataString.str()<<endl;

output = 1; 2; 3; 4; 5; 6;

2
ответ дан Awais Rafique 15 August 2018 в 14:45
поделиться
  • 1
    Как правило, ответы гораздо полезнее, если они включают объяснение того, что должен делать код, и почему это решает проблему, не представляя других. – Dan Cornilescu 24 April 2016 в 17:01
  • 2
    Это сработало!. короткий и сладкий. Спасибо. – Amjay 6 December 2016 в 11:00
string join(const vector<string> & v, const string & delimiter = ",") {
    string out;
    if (auto i = v.begin(), e = v.end(); i != e) {
        out += *i++;
        for (; i != e; ++i) out.append(delimiter).append(*i);
    }
    return out;
}

Несколько моментов:

  • вам не требуется дополнительное условие, чтобы избежать лишнего ограничивающего ограничителя
  • , убедитесь, что вы не сработали, когда вектор пуст
  • не создает кучу временных рядов (например, не делайте этого: x = x + d + y)
1
ответ дан Glen Knowles 15 August 2018 в 14:45
поделиться

Это расширение для двух ответов, уже представленных выше, поскольку производительность во время исполнения показалась темой комментариев. Я добавил бы его в качестве комментариев, но у меня еще нет этой привилегии.

Я тестировал 2 реализации для производительности во время исполнения с использованием Visual Studio 2015:

Использование stringstream:

std::stringstream result;
auto it = vec.begin();
result << (unsigned short)*it++;
for (; it != vec.end(); it++) {
    result << delimiter;
    result << (unsigned short)*it;
}
return result.str();

Использование accumulate:

std::string result = std::accumulate(std::next(vec.begin()), vec.end(),
    std::to_string(vec[0]),
    [&delimiter](std::string& a, uint8_t b) {
    return a + delimiter+ std::to_string(b);
});
return result;

Производительность выполнения сборки сборки была близка к парам тонкостей.

Реализация накопления была немного быстрее (20-50 мс, ~ 10-30% от общей продолжительности (~ 180 мс) на 1000 итераций по 256-элементному вектору). Однако реализация accumulate была только быстрее, когда параметр a для функции лямбда был передан по ссылке. Передача параметра a по значению привела к аналогичной разнице во времени во время реализации stringstream. Реализация accumulate также улучшилась, когда возвратная строка была возвращена напрямую, а не назначена локальной переменной, которая была немедленно возвращена. YMMV с другими компиляторами C ++.

Сборка Debug была в 5-10 раз медленнее с использованием accumulate, поэтому я думаю, что добавление дополнительной строки, отмеченное в нескольких комментариях выше, разрешено оптимизатором.

Я искал конкретную реализацию, используя vector значений uint8_t. Полный тестовый код:

#include <vector>
#include <iostream>
#include <sstream>
#include <numeric>
#include <chrono>

using namespace std;
typedef vector<uint8_t> uint8_vec_t;

string concat_stream(const uint8_vec_t& vec, string& delim = string(" "));
string concat_accumulate(const uint8_vec_t& vec, string& delim = string(" "));

string concat_stream(const uint8_vec_t& vec, string& delimiter)
{
    stringstream result;

    auto it = vec.begin();
    result << (unsigned short)*it++;
    for (; it != vec.end(); it++) {
        result << delimiter;
        result << (unsigned short)*it;
    }
    return result.str();
}

string concat_accumulate(const uint8_vec_t& vec, string& delimiter)
{
    return accumulate(next(vec.begin()), vec.end(),
        to_string(vec[0]),
        [&delimiter](string& a, uint8_t b) {
        return a + delimiter + to_string(b);
    });
}

int main()
{
    const int elements(256);
    const int iterations(1000);

    uint8_vec_t test(elements);
    iota(test.begin(), test.end(), 0);

    int i;
    auto stream_start = chrono::steady_clock::now();
    string join_with_stream;
    for (i = 0; i < iterations; ++i) {
        join_with_stream = concat_stream(test);
    }
    auto stream_end = chrono::steady_clock::now();

    auto acc_start = chrono::steady_clock::now();
    string join_with_acc;
    for (i = 0; i < iterations; ++i) {
        join_with_acc = concat_accumulate(test);
    }
    auto acc_end = chrono::steady_clock::now();

    cout << "Stream Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(stream_end - stream_start).count() << " ms" << endl;
    cout << "    result: " << join_with_stream << endl;

    cout << "Accumulate Results:" << endl;
    cout << "    elements: " << elements << endl;
    cout << "    iterations: " << iterations << endl;
    cout << "    runtime: " << chrono::duration<double, milli>(acc_end - acc_start).count() << " ms" << endl;
    cout << "    result:" << join_with_acc << endl;

    return 0;
}
4
ответ дан Matt Balvin 15 August 2018 в 14:45
поделиться
  • 1
    Мне нравится, что вы предоставили номера производительности - очень полезно для принятия решения так или иначе, спасибо! – cyberbisson 28 September 2017 в 14:35
std::string Gesture::getLabeledPointsString(const std::string delimiter) {
  return boost::join(getLabeledPoints(), delimiter);
}

Я не убежден в том, что в этот момент getLabeledPointsString убедится;)

6
ответ дан Matthieu M. 15 August 2018 в 14:45
поделиться
  • 1
    heheheheheh есть c ++ без boost? +1 для повышения, спасибо! – nkint 14 February 2012 в 21:08
  • 2
    @nkint: О, конечно, вы можете запрограммировать без повышения. Но это примерно так же сложно, как Python без его библиотек: вам просто нужно создать все инструменты самостоятельно;) – Matthieu M. 14 February 2012 в 21:37

более быстрый вариант:

vector<string> x = {"1", "2", "3"};
string res;
res.reserve(16);

std::accumulate(std::begin(x), std::end(x), 0,
                [&res](int &, string &s)
                {
                    if (!res.empty())
                    {
                        res.append(",");
                    }
                    res.append(s);
                    return 0;
               });

он не создает промежуточные строки, а просто выделяет память один раз для всего результата строки и добавляет каждый элемент в конец & res

9
ответ дан max.kondr 15 August 2018 в 14:45
поделиться
  • 1
    Выглядит аккуратно, но разве это не создало бы много строк в этом процессе? Любой способ улучшить это с помощью потокового потока? – oferei 31 March 2016 в 07:50
  • 2
    Нет, sttringsream замедляется еще больше. на самом деле, если у вас есть только контейнер строк, лучше написать обычный цикл for, например code; result.reserve (128); для (auto & amp; it: x) {if (! result.emty ()) {result.append (& quot;, "); } result.append (it); } code – max.kondr 1 April 2016 в 21:28
  • 3
    Звучит разумно, но это не то, что делает код выше. Это не добавление - это генерирование новых строк. – oferei 3 April 2016 в 10:00
  • 4
    Вы используете accumulate(), но полностью игнорируете этот результат. Вместо этого вы должны использовать std::for_each(). – Alexis Wilke 12 July 2016 в 23:07
  • 5
    Фактически возвращаемое значение этого вызова функции равно 0 (см. lambda - & gt; return 0;). но 'res' содержит строку результата – max.kondr 15 July 2016 в 06:13
  • 6
    Знаете ли вы, что accumulate ожидает, что его функция не будет иметь побочных эффектов? Этот код лучше выражать как for_each. – xtofl 13 September 2016 в 11:52
  • 7
    Вы можете избежать условного, если вы начинаете с begin(x)+1, а *begin(x) - как начальный элемент. – xtofl 13 September 2016 в 11:57
  • 8
    любая причина, по которой вы передаете неконстантные ссылки? – user463035818 9 May 2018 в 11:09

Еще один способ сделать это:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

template <typename T>
string join(const T& v, const string& delim) {
    ostringstream s;
    for (const auto& i : v) {
        if (&i != &v[0]) {
            s << delim;
        }
        s << i;
    }
    return s.str();
}

int main() {
    cout << join(vector<int>({1, 2, 3, 4, 5}), ",") << endl;
}

(c ++ 11 для цикла и «авто»)

8
ответ дан Shadow2531 15 August 2018 в 14:45
поделиться
9
ответ дан max.kondr 5 September 2018 в 13:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: