Is it even possible to concatenate vectors in Rust? If so, is there an elegant way to do so? I have something like this:
let mut a = vec![1, 2, 3]; let b = vec![4, 5, 6]; for val in &b { a.push(val); } Does anyone know of a better way?
The structure std::vec::Vec has method append():
fn append(&mut self, other: &mut Vec<T>) Moves all the elements of
otherintoSelf, leavingotherempty.
From your example, the following code will concatenate two vectors by mutating a and b:
fn main() { let mut a = vec![1, 2, 3]; let mut b = vec![4, 5, 6]; a.append(&mut b); assert_eq!(a, [1, 2, 3, 4, 5, 6]); assert_eq!(b, []); } Alternatively, you can use Extend::extend() to append all elements of something that can be turned into an iterator (like Vec) to a given vector:
let mut a = vec![1, 2, 3]; let b = vec![4, 5, 6]; a.extend(b); assert_eq!(a, [1, 2, 3, 4, 5, 6]); // b is moved and can't be used anymore Note that the vector b is moved instead of emptied. If your vectors contain elements that implement Copy, you can pass an immutable reference to one vector to extend() instead in order to avoid the move. In that case the vector b is not changed:
let mut a = vec![1, 2, 3]; let b = vec![4, 5, 6]; a.extend(&b); assert_eq!(a, [1, 2, 3, 4, 5, 6]); assert_eq!(b, [4, 5, 6]); I can't make it in one line. Damian Dziaduch
It is possible to do it in one line by using chain():
let c: Vec<i32> = a.into_iter().chain(b).collect(); // Consumed let c: Vec<&i32> = a.iter().chain(&b).collect(); // Referenced let c: Vec<i32> = a.iter().cloned().chain(b.iter().cloned()).collect(); // Cloned let c: Vec<i32> = a.iter().copied().chain(b.iter().copied()).collect(); // Copied There are infinite ways.
a and b are not available anymore, the result is free to do what it want. Reference just borrow both vector, so you need to keep their alive as long the result want to live. Clone and Copy are very close, the first one can be expensive, the second one should be cheap. They just use both vector as a source without need them latter, so the result become free to live as long as it want as well that a and b. Hope it's clear.extend?Regarding the performance, slice::concat, append and extend are about the same. If you don't need the results immediately, making it a chained iterator is the fastest; if you need to collect(), it is the slowest:
#![feature(test)] extern crate test; use test::Bencher; #[bench] fn bench_concat___init__(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; }); } #[bench] fn bench_concat_append(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; x.append(&mut y) }); } #[bench] fn bench_concat_extend(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; x.extend(y) }); } #[bench] fn bench_concat_concat(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; [x, y].concat() }); } #[bench] fn bench_concat_iter_chain(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; x.into_iter().chain(y.into_iter()) }); } #[bench] fn bench_concat_iter_chain_collect(b: &mut Bencher) { b.iter(|| { let mut x = vec![1i32; 100000]; let mut y = vec![2i32; 100000]; x.into_iter().chain(y.into_iter()).collect::<Vec<i32>>() }); } running 6 tests test bench_concat___init__ ... bench: 27,261 ns/iter (+/- 3,129) test bench_concat_append ... bench: 52,820 ns/iter (+/- 9,243) test bench_concat_concat ... bench: 53,566 ns/iter (+/- 5,748) test bench_concat_extend ... bench: 53,920 ns/iter (+/- 7,329) test bench_concat_iter_chain ... bench: 26,901 ns/iter (+/- 1,306) test bench_concat_iter_chain_collect ... bench: 190,334 ns/iter (+/- 16,107) bench_concat_iter_chain do nothing, iterator are lazyrustc 1.55.0-nightly (885399992 2021-07-06) have much better result, houra !benches folder in your crate. Ensure the nightly toolchain is installed with rustup install nightly and you can run the benchmarks with cargo +nightly benchlet v1 = vec![1, 2, 3]; let v2 = vec![4, 5, 6]; let v3 = vec![v1, v2].concat(); // [1, 2, 3, 4, 5, 6] slice::concat needs to clone each element.
a.extend(b)?