What is the best way to repeat the elements in a vector in Rust?
Asked Answered
S

5

14

I found this way, but it seems too verbose for such a common action:

fn double_vec(vec: Vec<i32>) -> Vec<i32> {
    let mut vec1 = vec.clone();
    let vec2 = vec.clone();

    vec1.extend(vec2);

    vec1
}

I know that in JavaScript it could be just arr2 = [...arr1, ...arr1].

Serotherapy answered 1/12, 2017 at 20:34 Comment(1)
Even in this solution, only one of those .clone()s is necessary.Widely
D
10

You can use the concat method for this, it's simple:

fn double_vec(v: Vec<i32>) -> Vec<i32> {
    [&v[..], &v[..]].concat()
}

Unfortunately we have to make the vectors slices explicitly (here &v[..]); but otherwise this method is good because it allocates the result to the needed size directly and then does the copies.

Disadvantaged answered 2/12, 2017 at 13:27 Comment(0)
W
13

"Doubling a vector" isn't something that's really done very often so there's no shortcut for it. In addition, it matters what is inside the Vec because that changes what operations can be performed on it. In this specific example, the following code works:

let x = vec![1, 2, 3];

let y: Vec<_> = x.iter().cycle().take(x.len() * 2).collect();

println!("{:?}", y); //[1, 2, 3, 1, 2, 3]

The cycle() method requires that the items in the Iterator implement the Clone trait so that the items can be duplicated. So if the items in your Vec implement Clone, then this will work. Since immutable references (&) implement Clone, a Vec<&Something> will work but mutable references (&mut) do not implement Clone and thus a Vec<&mut Something> will not work.

Note that even if a type does not implement Clone, you can still clone references to that type:

struct Test;

fn test_if_clone<T: Clone>(_x: T) {}

fn main() {
    let x = Test;

    test_if_clone(x); //error[E0277]: the trait bound `Test: std::clone::Clone` is not satisfied

    let y = &x;

    test_if_clone(y); //ok
}
Wade answered 1/12, 2017 at 20:57 Comment(0)
D
10

You can use the concat method for this, it's simple:

fn double_vec(v: Vec<i32>) -> Vec<i32> {
    [&v[..], &v[..]].concat()
}

Unfortunately we have to make the vectors slices explicitly (here &v[..]); but otherwise this method is good because it allocates the result to the needed size directly and then does the copies.

Disadvantaged answered 2/12, 2017 at 13:27 Comment(0)
S
7

Building on Wesley's answer, you can also use chain to glue two iterables together, one after the other. In the below example I use the same Vec's iter() method twice:

let x = vec![1, 2, 3];

let y: Vec<_> = x.iter().chain(x.iter()).collect();

println!("{:?}", y); //[1, 2, 3, 1, 2, 3]
Sidonius answered 1/12, 2017 at 21:2 Comment(1)
One thing that's probably worth mentioning is that the type of y is Vec<&{integer}> not Vec<{integer>. This is a good solution though since it allows you to handle vectors whose contents can't be cloned.Wade
P
6

The iterator methods are a likely to be a lot less efficient than a straight memcpy that vector extension is.

You own code does a clone too many; you can just reuse the by-value input:

fn double_vec(mut vec: Vec<i32>) -> Vec<i32> {
    let clone = vec.clone();
    vec.extend(clone);
    vec
}

However, the nature of a Vec means this is likely to require a copy even if you managed to remove that clone, so you're not generally gaining much over just using concat.

Using concat on slices is fairly efficient, as it will preallocate the Vec in advance and then perform an efficient extend_from_slice. However, this does mean it's no longer particularly sensible to take a Vec as input; writing the following is strictly more flexible.

fn double_slice(slice: &[i32]) -> Vec<i32> {
    [slice, slice].concat()
}
Perihelion answered 2/12, 2017 at 13:42 Comment(0)
D
3

Since Rust 1.53, Vec::extend_from_within makes it possible to more efficiently double a vector:

fn double_vec(vec: &mut Vec<i32>) {
    vec.extend_from_within(..);
}
Devolve answered 29/11, 2021 at 21:51 Comment(1)
vec.repeat(1) would also work. extend_from_within() provides flexibility which parts to copy, repeat() about the number of times the part is copied.Residuary

© 2022 - 2024 — McMap. All rights reserved.