¿Cuál es la mejor manera de concatenar vectores en Rust?

Resuelto Joe Thomas asked hace 7 años • 6 respuestas

¿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?

Joe Thomas avatar Nov 25 '16 01:11 Joe Thomas
Aceptado

La estructura std::vec::Vectiene método append():

fn append(&mut self, other: &mut Vec<T>)

Mueve todos los elementos de othera Self, dejándolos othervací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 bse 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 bno 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]);
 avatar Nov 24 '2016 22:11

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.

Stargateur avatar Jun 07 '2019 08:06 Stargateur

En cuanto al rendimiento, slice::concaty appendson extendmá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)
Tianyi Shi avatar Sep 15 '2020 13:09 Tianyi Shi