How do I convert Vec of i32 to string


#1

It seems simple enough. I have a vector of i32 values. I just want to make that into a string. in my example, stuff_str would be “55208”;

Here’s the code:

let stuff = vec![5, 5, 2, 0, 8];
let stuff_str: String = stuff.into_iter().collect::<i32>().to_string();

But I get compile error:

   |
52 |         let stuff_str: String = stuff.into_iter().collect::<i32>().to_string();
   |                                                   ^^^^^^^ a collection of type `i32` cannot be built from an iterator over elements of type `{integer}`
   |

I tried a few different things but am having a block here.

Thnx for the help
Matt


#2

You’ll want to apply to_string to each item, rather than to the collection like you are doing now.
If I’m not mistaken (on mobile, so can’t really check): .map(to-string), which should result in a Vec<String>
After that, there should be an applicable join method to turn your Vec<String> into a String.


#3

So are you trying to make a Vec<String> of the individual numbers? Or are you trying to get a string representation of the entire vec?

It sounds like you want the latter, in which case you can do let stuff_str = format!("{:?}", stuff); to get a String of the Vec's Debug representation. The formatting wouldn’t exactly match what you’re after though.


#4

format!("{:?}", stuff) returns something like “[5, 5, 2, 0, 8]”

I want “55208”.

Matt


#5

I thought that might be the case. This should do the trick, though I’m not sure how much I like it

https://play.rust-lang.org/?gist=5eb348202fc86bb838c66c12e39eae52&version=stable&mode=debug&edition=2015


#6

Use:

    let stuff_str: String = stuff.into_iter().map(|i| i.to_string()).collect::<String>();

Note that i.to_string() is a bit inefficient, there’s crates that print numbers to chars faster, but the general method remains.


#7

Ah, that’s even better. For some reason it didn’t occur to me to use collect::<String>(). Guess I’m too used to seeing it done with Vecs!


#8

Can go via char first as well:

fn main() {
    let stuff = vec![5, 5, 2, 0, 8];
    let stuff_str: String = stuff
        .into_iter()
        .map(|d| std::char::from_digit(d, 10).unwrap())
        .collect();
    println!("{}", stuff_str);
}

#9

With fmt::Write its possible to do it without temporary String allocation:

https://play.rust-lang.org/?gist=d6cc188a21b43c4b49f581a19c410b29&version=stable&mode=debug&edition=2015


#10

Just transformed kornel’s solution into functional style:

use std::fmt::Write;

fn join(a: &[i32]) -> String {
    a.iter().fold(String::new(),|mut s,&n| {write!(s,"{}",n).ok(); s})
}

fn main() {
    println!("{}",join(&vec![1,2,3]));
}

#11

You don’t even need to consume the vector, you don’t need the lambda, and you don’t need the type annotation in both places:

let stuff_str: String = stuff.iter().map(ToString::to_string).collect();

#12

If I understood your intent correctly, then to_string and format! variants suggested in this thread are slightly incorrect, as they do not check if number falls into 0…9 range. Plus they are somewhat ineffective, as they allocate a new string for each number. Alternative solution which handles those issues can look like this:

let stuff_str: String = stuff.into_iter().map(|b| {
    assert!(b >=0 && b <= 9);
    (b as u8 + 48) as char
}).collect();

Here I use the fact that digits in ASCII (and as a consequence in UTF-8) are ordered and ‘0’ is 48 if represented as a byte.


#13

You can just use std::char::from_digit, like in one of the examples above.