let assume that we have a vector of points written as a flat sequence of integers. size of vector is precise and we want to convert it to vector of Point
structs. So my conversion currently looks like this.
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Point {
fn new(x: i32, y : i32) -> Point {
Point{x,y}
}
}
impl From<Point> for String {
fn from(point: Point) -> String {
format!("({},{})", point.x, point.y)
}
}
fn main() {
let vec = vec![2,1,4,3,6,5]; // We want convert that
let even = vec.iter().step_by(2);
let odd = vec.iter().skip(1).step_by(2);
let points: Vec<Point>
= even.zip(odd)
.map(|(x,y)|Point::new(*x,*y))
.collect();
println!("{:?}", points);
}
Works like a charm, until we want to add z
component, and peek into three elements per cycle. I haven't found any appropriate methods from docs. So, is there already a generic way to iterate over slices of some size over vector and unpack it into my struct(s) or there's no such way and I should implement such iterator myself? Is it a signal to use some heavier machinery like serde
.
It is easy to do in std for slices using chunks_exact.
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
z: i32,
}
impl Point {
fn new(x: i32, y : i32, z: i32) -> Point {
Point{x,y, z}
}
}
fn main() {
let vec = vec![2,1,4,3,6,5];
let points: Vec<Point>
= vec.chunks_exact(3)
.map(|chunk|Point::new(chunk[0], chunk[1], chunk[2]))
.collect();
println!("{:?}", points);
}
I don't think there is a pre-done method for it, but you can easily write code that can be adjusted pretty quickly to include a third z
component, similar to this (Playground):
#[derive(Debug, Default)]
struct PointBuilder {
x: Option<i32>,
y: Option<i32>,
// add a z here
}
impl PointBuilder {
fn add(&mut self, value: i32) {
if self.x.is_none() {
self.x = Some(value);
} else if self.y.is_none() {
self.y = Some(value);
}
// add a z here
}
fn try_build(&self) -> Option<Point> {
// and one last z in this match expression
match (self.x, self.y) {
(Some(x), Some(y)) => Some(Point::new(x, y)),
_ => None,
}
}
}
fn convert_to_points(data: impl IntoIterator<Item = i32>) -> Vec<Point> {
data.into_iter()
.fold((PointBuilder::default(), Vec::<Point>::new()), |(mut builder, mut points), value| {
builder.add(value);
if let Some(point) = builder.try_build() {
points.push(point);
(PointBuilder::default(), points)
} else {
(builder, points)
}
})
.1
}
fn main() {
let vec = vec![2, 1, 4, 3, 6, 5]; // We want convert that
let points = convert_to_points(vec);
println!("{:?}", points);
}
This could of course be done as a proc-macro-derive code generator if you need this for dozens of structs, but I'm not aware of any library that has this implemented already, so it depends on your use case if it'd be worth the effort.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With