264

I wasn't able to find the Rust equivalent for the "join" operator over a vector of Strings. I have a Vec<String> and I'd like to join them as a single String:

let string_list = vec!["Foo".to_string(),"Bar".to_string()];
let joined = something::join(string_list,"-");
assert_eq!("Foo-Bar", joined);

Related:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Davide Aversa
  • 5,628
  • 6
  • 28
  • 40

3 Answers3

348

In Rust 1.3.0 and later, join is available:

fn main() {
    let string_list = vec!["Foo".to_string(),"Bar".to_string()];
    let joined = string_list.join("-");
    assert_eq!("Foo-Bar", joined);
}

Before 1.3.0 this method was called connect:

let joined = string_list.connect("-");

Note that you do not need to import anything since the methods are automatically imported by the standard library prelude.

join copies elements of the vector, it does not move them, thus it preserves the contents of the vector, rather than destroying it.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
MatthewG
  • 8,583
  • 2
  • 25
  • 27
  • 8
    Perhaps this has changed, but `SliceConcatExt` is nightly-only. –  Jul 10 '17 at 01:58
  • 5
    @Evert The trait is marked unstable, but its methods are stable so you can use them. You don't need to explicitly `use` the trait because it's in the prelude. – interjay Jul 28 '17 at 16:09
  • @shepmaster Is there an iterator equivalent that doesn't require me to collect the vector first? – Steve Powell Jan 18 '18 at 17:32
  • 1
    @StevePowell [What's an idiomatic way to print an iterator separated by spaces in Rust?](https://stackoverflow.com/q/36941851/155423). – Shepmaster Jan 18 '18 at 17:41
  • 1
    @shepmaster If I read your 'reply' correctly, there is a `join` in `itertools`. – Steve Powell Jan 21 '18 at 19:10
  • 1
    @StevePowell yes. Comments are ephemeral, Q&A are not. Linking to an answer with examples is better for the site and all future visitors instead of putting random answers in a comment that will be deleted. Q&A can be upvoted to let future people know that an answer was useful and encourage more participation in the site.. – Shepmaster Jan 21 '18 at 19:13
  • 7
    Thank you @shepmaster. Unfortunately, your unadorned reference to another answer was rather cryptic, so it was not at all clear which part of that answer was relevant. Though your comments, corrections and answers are invariably excellent your style is condescending and off-putting. – Steve Powell Jan 22 '18 at 22:32
  • `join` does not work on the empty char literal? – Alper Dec 19 '20 at 08:26
  • Does this copy the data from the vector or move it? – FreelanceConsultant Apr 27 '23 at 11:26
  • Tried in playground, and apparently the behavior is to copy the elements, not move them. – FreelanceConsultant Apr 27 '23 at 11:30
31

As mentioned by Wilfred, SliceConcatExt::connect has been deprecated since version 1.3.0 in favour of SliceConcatExt::join:

let joined = string_list.join("-");
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Danilo Bargen
  • 18,626
  • 15
  • 91
  • 127
16

There is a function from the itertools crate also called join which joins an iterator:

extern crate itertools; // 0.7.8

use itertools::free::join;
use std::fmt;

pub struct MyScores {
    scores: Vec<i16>,
}

impl fmt::Display for MyScores {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str("MyScores(")?;
        fmt.write_str(&join(&self.scores[..], &","))?;
        fmt.write_str(")")?;
        Ok(())
    }
}

fn main() {
    let my_scores = MyScores {
        scores: vec![12, 23, 34, 45],
    };
    println!("{}", my_scores); // outputs MyScores(12,23,34,45)
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Nick Linker
  • 1,013
  • 9
  • 10
  • 12
    Users of this code should be aware that it allocates a potentially large string just to throw it away. It is more efficient to write the strings directly to the output. See also [What's an idiomatic way to print an iterator separated by spaces in Rust?](https://stackoverflow.com/q/36941851/155423), [In Rust, what is the best way to print something between each value in a container?](https://stackoverflow.com/q/26644486/155423). – Shepmaster Jul 05 '18 at 12:44
  • 3
    Understandable, although the question was about the `join`, not the ways how to optimize the formatting algorithm, no? – Nick Linker Jul 05 '18 at 12:52
  • 8
    `collect` + `join` is faster and adds no dependencies, see this [gist](https://gist.github.com/green-s/fbd0d374b290781ac9b3f8ff03e3245d) for a benchmark – murla Sep 23 '19 at 16:50
  • @murla yeah but it's annoying source code when T implements Display and the separator is a string, but vec.join won't convert them for you. `.iter().map(|x| x.to_string()).collect::>().join(", ")` – theonlygusti Nov 29 '22 at 03:58