¿Cuál es la mejor manera de concatenar vectores en Rust?
¿Es incluso posible concatenar vectores en Rust? Si es así, ¿existe alguna manera elegante de hacerlo? Tengo algo como esto:
let mut a = vec![1, 2, 3];
let b = vec![4, 5, 6];
for val in &b {
a.push(val);
}
¿Alguien sabe de una manera mejor?
La estructura std::vec::Vec
tiene método append()
:
fn append(&mut self, other: &mut Vec<T>)
Mueve todos los elementos de
other
aSelf
, dejándolosother
vacíos.
A partir de su ejemplo, el siguiente código concatenará dos vectores mutando a
y 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, []);
}
Alternativamente, puedes usar Extend::extend()
para agregar todos los elementos de algo que se pueda convertir en un iterador (como Vec
) a un vector determinado:
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
Tenga en cuenta que el vector b
se mueve en lugar de vaciarse. Si sus vectores contienen elementos que implementan Copy
, puede pasar una referencia inmutable a un vector extend()
para evitar el movimiento. En ese caso el vector b
no se cambia:
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]);
No puedo hacerlo en una sola línea. Damian Dziaduch
Es posible hacerlo en una línea usando chain()
:
let c: Vec<i32> = a.into_iter().chain(b.into_iter()).collect(); // Consumed
let c: Vec<&i32> = a.iter().chain(b.iter()).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
Hay infinitas maneras.
En cuanto al rendimiento, slice::concat
y append
son extend
más o menos iguales. Si no necesita los resultados inmediatamente, convertirlo en un iterador encadenado es lo más rápido; si es necesario collect()
, es el más lento:
#![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)