Join Vec<String> into String after prepending each value

Viewed 112

If given a Vec<String> of values, how can I get back a String where each has been prepended with -a . Here is my solution, and it works, but it feels obtuse, so I'd like to know the best way to do this.

  • input: ["foo", "bar"]
  • output: -a foo -a bar

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5558637f3462414cd57926db0faaf20b

fn f(args: Vec<String>) -> String { 
    args.into_iter()
    .map(|s| format!("-a {}", s))
    .collect::<Vec<String>>().join(" ")
}

fn main() {
    let args = ["foo", "bar"].iter().map(|&s| s.into()).collect();
    println!("{}", f(args));
}
2 Answers

It's concise but there are two points of inefficiency here:

  • creating a new vec instead of modifying the vec in place
  • creating a lot of strings when you just want one string

A first improvement would be to just prepend to the strings in place but if you want something more direct you could do

fn f(args: Vec<String>) -> String {
    let mut s = String::new();
    for arg in args {
        if !s.is_empty() {
            s.push(' ');
        }
        s.push_str("-a ");
        s.push_str(&arg);
    }
    s
}

If performance is irrelevant for your use case, then there's no problem with your code. Without additional crates join does need a vec today (you could use intersperse but only in nightly).

If you can accept a slight loss of speed - here is a shorter solution using fold:

fn f(args: Vec<String>) -> String { 
    args.iter()
    .fold(String::new(), |s1, s2| s1 + " -a " + s2)
    .trim_start().to_string()
}
Related