Reputation: 11269
How to split a vector
let v: Vec<u8>; // vector with size x
into a vector of vectors of maxsize n? Pseudocode:
let n: usize = 1024;
let chunks_list: Vec<Vec<u8>> = chunks(v, n);
or using slices (to avoid copying):
let v: &[u8];
let chunks_list: Vec<&[u8]> = chunks(v, n);
Upvotes: 20
Views: 18474
Reputation: 11269
There is a method already existing for slices:
pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T>
Returns an iterator over
chunk_size
elements of the slice at a time, starting at the beginning of the slice. The chunks are slices and do not overlap. Ifchunk_size
does not divide the length of the slice, then the last chunk will not have lengthchunk_size
.
There is also chunks_mut
for mutability as well as chunks_exact
and chunks_exact_mut
if the last chunk has to respect the size n
, along with the unsafe as_chunks_unchecked
in case we assume there is no remainder, see below example:
fn main() {
let v: [u8; 5] = *b"lorem";
let n = 2;
let chunks = v.chunks(n);
let chunks_list: Vec<&[u8]> = chunks.collect();
println!("{:?}", chunks_list);
}
Using a slice instead of vectors has some benefits, notably avoiding the overhead of copying.
Upvotes: 4
Reputation: 432189
If it's required to take a Vec
and split it into multiple Vec
s, I'd use Itertools::chunks
. This takes an iterator and returns an iterator of iterators. You can then choose to collect both the inner and outer iterators into Vec
s:
use itertools::Itertools; // 0.10.0
fn main() {
let v = vec![String::from("A"), String::from("B"), String::from("C")];
let x: Vec<Vec<String>> = v.into_iter().chunks(2).into_iter().map(|c| c.collect()).collect();
eprintln!("{:?}", x);
}
[["A", "B"], ["C"]]
This has the benefit of taking ownership of each value in the original vector. No data needs to be copied, but it does need to be moved. If you can use slices instead, it's much better to use slice::chunks
.
Upvotes: 2
Reputation: 382474
Rust slices already contain the necessary method for that: chunks.
Starting from this:
let src: Vec<u8> = vec![1, 2, 3, 4, 5];
you can get a vector of slices (no copy):
let dst: Vec<&[u8]> = src.chunks(3).collect();
or a vector of vectors (slower, heavier):
let dst: Vec<Vec<u8>> = src.chunks(3).map(|s| s.into()).collect();
Upvotes: 27
Reputation: 16248
Here is one approach:
use std::{usize, vec};
fn chunks(data: Vec<u8>, chunk_size: usize) -> Vec<Vec<u8>> {
let mut results = vec![];
let mut current = vec![];
for i in data {
if current.len() >= chunk_size {
results.push(current);
current = vec![];
}
current.push(i);
}
results.push(current);
return results;
}
fn main() {
let v: Vec<u8> = (1..100).collect();
let n: usize = 24;
let chunks_list = chunks(v, n);
println!("{:#?}", chunks_list);
}
Upvotes: 1