简体   繁体   中英

C++ - How do I create a vector where every element is a single digit from an input string?

I'm trying to write a function that takes a user input of digits, eg 830948234681764 and creates a vector with as many values as the full length of that input, and creates one element for every digit:

Input: 830948234681764

  • index - value
    • 0 - 8
    • 1 - 3
    • 2 - 0
    • 3 - 9
    • 4 - 4
    • 5 - 8

etc

I've had issues using maths to extract the individual digits because the sequence has to be potentially several thousand characters long.

Using a string, however, means that each element of the vector becomes that digits's ascii code, and I'm not sure how to convert them to the original values.

Here's the meat of the code:

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

Whether it's converting the array from ascii to int values afterwards, or taking each character and converting it to an int before injecting it into the vector, I'm new to C++ and am a bit stuck figuring this one out. Any help would be much appreciated!

Cheers

One way to do it is the push the successive digits into an initially empty vector.

 std::string s = "07563157289";

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

An alternative is to first create the vector with the right size, then use a loop over indices to fill the vector

 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';
 }

It is slightly more efficient with huge strings, because it avoids the costs of (hidden) reallocations of the underlying array.

EDIT : I compiled several versions (with g++ --std=c++11 -Os -S) to have a look on the code produced by the compiler.

The winner is

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

where the vector is first allocated to the right size, then filled with values. The loop is 5 machine instructions only.

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

And the same code is generated for the "declare vector with size + for loop with index" version (1st ex-aequo).

Using transform+back_inserter is 2x-longer and involves a costly call to an auxiliary procedure (about 50 instructions) for 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

You can avoid the loops and use 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'; });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM