How can I chunk a vector with non-copyable-cloneable items?

I want to spit my vector into small vectors, but the item type cannot be cloned. Is there any way I can still split it?
For example:

struct Foo {}

fn main() {
    let vector = vec![Foo {}; 10];
    let vectors: Vec<Vec<Foo>> = vector
        .chunks(2)
        .map(|sub_foos| sub_foos.into_vec())
        .collect();
}
let vectors: Vec<Vec<&Foo>> = vector
    .chunks(2)
    .map(|sub_foos| sub_foos.iter().collect())
    .collect();

I do want to get a Vec<Vec<Foo>> in this case.

If you can use nightly feature, then.

    let vectors: Vec<Vec<Foo>> = vector
        .into_iter()
        .array_chunks::<2>()
        .map(|sub_foos| sub_foos.into())
        .collect();

If you cannot:

    let mut temp = vec![];
    let vectors: Vec<Vec<Foo>> = vector
        .into_iter()
        .filter_map(|foo| {
            temp.push(foo);
            (temp.len() == 2).then(|| std::mem::take(&mut temp))
        })
        .collect();

Then you can't use chunks() because it gives you references. I don't think there's a stable, ready-made combinator for this in std; you may want to watch out for array_chunks() becoming stable. In the meantime, use a loop.

for (i, v) in vector.into_iter().enumerate() {
    tmp.push(v);
    if tmp.len() == 2 {
        vectors.push(core::mem::take(&mut tmp));
    }
}

if tmp.len() > 0 {
    vectors.push(tmp);
}

Itertools offers a chunks method:

use itertools::Itertools;

#[derive(PartialEq, Debug)]
struct Foo {}

fn main() {
    let vector = vec![Foo {}, Foo {}, Foo {}, Foo {}];

    let mut vectors: Vec<Vec<Foo>> = vec![];

    for chunk in &vector.into_iter().chunks(2) {
        vectors.push(chunk.collect());
    }

    assert_eq!(vectors, vec![vec![Foo {}, Foo {}], vec![Foo {}, Foo {}]]);
}

Playground.


Instead of a for loop you can also use this:

    let vectors: Vec<Vec<Foo>> = vector
        .into_iter()
        .chunks(2)
        .into_iter()
        .map(|c| c.collect())
        .collect();
1 Like

And the closure is unnecessary, too, you can just .map(Iterator::collect).

1 Like

Here's another way without using third party dependencies:

#[derive(Debug, PartialEq)] // Just for the assert
struct Foo {}

fn main() {
    let vector = vec![Foo {}, Foo {}, Foo {}, Foo {}];
    
    let chunk_size = 2;
    
    let chunks = (vector.len() + chunk_size - 1) / chunk_size;
    let mut iter = vector.into_iter();
    let vectors: Vec<Vec<Foo>> = (0..chunks)
        .map(|_| iter.by_ref().take(chunk_size).collect())
        .collect();
    
    assert_eq!(vectors, vec![vec![Foo {}, Foo {}], vec![Foo {}, Foo {}]]);
}
1 Like

It seems that this array_chunks takes a constant, which I can't offer at compile time.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.