Я пытаюсь написать функцию, которая принимает пользовательский ввод цифр, например, 830948234681764 и создает вектор с таким количеством значений, как полная длина этого ввода, и создает один элемент для каждой цифры:

Ввод: 830948234681764

  • индекс - значение
    • 0 - 8
    • 1 - 3
    • 2 - 0
    • 3 - 9
    • 4 - 4
    • 5 - 8

Др

У меня были проблемы с использованием математики для извлечения отдельных цифр, потому что последовательность должна быть длиной в несколько тысяч символов.

Использование строки, однако, означает, что каждый элемент вектора становится кодом ascii этих цифр, и я не уверен, как преобразовать их в исходные значения.

Вот основная часть кода:

    string s = "12345"
    int size = s.length();
    std::vector <double> v (size);
    for (int i = 0; i < size; i++) {
        v[i] = s[i];
}

Будь то преобразование массива из значений ascii в значения int впоследствии или взятие каждого символа и преобразование его в целое число перед тем, как вставить его в вектор, я новичок в C ++ и немного застрял, пытаясь понять это. Любая помощь приветствуется!

Ура

1
Sentinel 28 Май 2017 в 17:02

2 ответа

Лучший ответ

Один из способов сделать это - вставить последовательные цифры в изначально пустой вектор.

 std::string s = "07563157289";

 std::vector<int> v;
 for (auto c : s) {                // for each char in s
    v.push_back(c - '0');
 }

Альтернатива состоит в том, чтобы сначала создать вектор с правильным размером, а затем использовать цикл над индексами, чтобы заполнить вектор

 unsigned size = s.size();
 std::vector<int> v(size);
 for (unsigned i=0; i<size; ++i) {     // for i in {0,1, ..size-1}
    v[i] = s[i] - '0';
 }

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

РЕДАКТИРОВАТЬ : я скомпилировал несколько версий (с g ++ --std = c ++ 11 -Os -S), чтобы посмотреть на код, созданный компилятором.

Победитель

std::vector<int> digits_transform_alloc(const std::string &s)
{
   std::vector<int> v(s.size());
   std::transform(s.begin(), s.end(), 
                  v.begin(),
                  [](char ch) { return ch - '0';});
   return v;
}

Где вектор сначала присваивается правильному размеру, а затем заполняется значениями. Цикл только 5 машинных инструкций.

.L61:
    cmpq    %r13, %rax
    je  .L66
    movl    $0, (%r12,%rax,4)
    incq    %rax
    jmp .L61

И тот же код генерируется для версии «объявить вектор с размером + для цикла с индексом» (1-й пример - aequo).

Использование transform + back_inserter в 2 раза длиннее и требует дорогостоящего вызова вспомогательной процедуры (около 50 инструкций) для emplace_back

.L48:
    cmpq    %r12, %rbp
    je  .L54
    movsbl  0(%rbp), %edx
    leaq    12(%rsp), %rsi
    movq    %rbx, %rdi
    subl    $48, %edx
    movl    %edx, 12(%rsp)
.LEHB2:
    call    _ZNSt6vectorIiSaIiEE12emplace_backIIiEEEvDpOT_
.LEHE2:
    incq    %rbp
    jmp .L48
9
Michel Billaud 29 Май 2017 в 12:55

Вы можете избежать циклов и использовать std::transform.

#include <algorithm>
#include <vector>
#include <iterator>
#include <string>
//...
std::string InputSequence;
std::vector <double> MainVector;
//...
std::transform(InputSequence.begin(), InputSequence.end(), 
               std::back_inserter(MainVector), [](char ch) { return ch - '0'; });
4
PaulMcKenzie 28 Май 2017 в 14:45