35

I want to take the x first and last elements from a vector and concatenate them. I have the following code:

fn main() {
    let v = (0u64 .. 10).collect::<Vec<_>>();
    let l = v.len();
    vec![v.iter().take(3), v.iter().skip(l-3)];
}

This gives me the error

error[E0308]: mismatched types
 --> <anon>:4:28
  |
4 |     vec![v.iter().take(3), v.iter().skip(l-3)];
  |                            ^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Take`, found struct `std::iter::Skip`
<anon>:4:5: 4:48 note: in this expansion of vec! (defined in <std macros>)
  |
  = note: expected type `std::iter::Take<std::slice::Iter<'_, u64>>`
  = note:    found type `std::iter::Skip<std::slice::Iter<'_, u64>>`

How do I get my vec of 1, 2, 3, 8, 9, 10? I am using Rust 1.12.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
The Unfun Cat
  • 29,987
  • 31
  • 114
  • 156

3 Answers3

58

Just use .concat() on a slice of slices:

fn main() {
    let v = (0u64 .. 10).collect::<Vec<_>>();
    let l = v.len();
    let first_and_last = [&v[..3], &v[l - 3..]].concat();
    println!("{:?}", first_and_last);
    // The output is `[0, 1, 2, 7, 8, 9]`
}

This creates a new vector, and it works with arbitrary number of slices.

(Playground link)

Coder-256
  • 5,212
  • 2
  • 23
  • 51
bluss
  • 12,472
  • 1
  • 49
  • 48
21

Ok, first of all, your initial sequence definition is wrong. You say you want 1, 2, 3, 8, 9, 10 as output, so it should look like:

    let v = (1u64 .. 11).collect::<Vec<_>>();

Next, you say you want to concatenate slices, so let's actually use slices:

    let head = &v[..3];
    let tail = &v[l-3..];

At this point, it's really down to which approach you like the most. You can turn those slices into iterators, chain, then collect...

    let v2: Vec<_> = head.iter().chain(tail.iter()).collect();

...or make a vec and extend it with the slices directly...

    let mut v3 = vec![];
    v3.extend_from_slice(head);
    v3.extend_from_slice(tail);

...or extend using more general iterators (which will become equivalent in the future with specialisation, but I don't believe it's as efficient just yet)...

    let mut v4: Vec<u64> = vec![];
    v4.extend(head);
    v4.extend(tail);

...or you could use Vec::with_capacity and push in a loop, or do the chained iterator thing, but using extend... but I have to stop at some point.

Full example code:

fn main() {
    let v = (1u64 .. 11).collect::<Vec<_>>();
    let l = v.len();

    let head = &v[..3];
    let tail = &v[l-3..];

    println!("head: {:?}", head);
    println!("tail: {:?}", tail);

    let v2: Vec<_> = head.iter().chain(tail.iter()).collect();
    println!("v2: {:?}", v2);

    let mut v3 = vec![];
    v3.extend_from_slice(head);
    v3.extend_from_slice(tail);
    println!("v3: {:?}", v3);

    // Explicit type to help inference.
    let mut v4: Vec<u64> = vec![];
    v4.extend(head);
    v4.extend(tail);
    println!("v4: {:?}", v4);
}
DK.
  • 55,277
  • 5
  • 189
  • 162
  • 2
    `extend()` should shortly be specialized to `extend_from_slice()`; it was merged a few days ago: [Specialize Vec::extend to Vec::extend_from_slice](https://github.com/rust-lang/rust/pull/37094). – ljedrz Oct 20 '16 at 12:50
  • Stable release of which is... 9-ish weeks away? Like I said, not *just yet.* – DK. Oct 20 '16 at 23:56
  • 2
    `let v = (1u64 .. 11).collect::>();` booo. `let v: Vec = (1..11).collect();` yaaay – Shepmaster Oct 21 '16 at 02:14
  • 1
    Why yes, just letting you know if you haven't seen that it was already merged. – ljedrz Oct 21 '16 at 02:55
8

You should collect() the results of the take() and extend() them with the collect()ed results of skip():

let mut p1 = v.iter().take(3).collect::<Vec<_>>();
let p2 = v.iter().skip(l-3);

p1.extend(p2);

println!("{:?}", p1);

Edit: as Neikos said, you don't even need to collect the result of skip(), since extend() accepts arguments implementing IntoIterator (which Skip does, as it is an Iterator).

Edit 2: your numbers are a bit off, though; in order to get 1, 2, 3, 8, 9, 10 you should declare v as follows:

let v = (1u64 .. 11).collect::<Vec<_>>();

Since the Range is left-closed and right-open.

ljedrz
  • 20,316
  • 4
  • 69
  • 97