# Reduce a vector into a vector of structs

Hi guys, I have a sequence that is a struct where I have a starting value, a delta and a repeat, as in

``````pub struct Sequence {
start: u32,
delta: u32,
repeat: u32,
}
``````

what I want to do is that given a vector of number, I can convert that into a vector of Sequence. Examples:

• [1, 2, 3, 4] corresponds to the following sequence
``````Sequence {
start= 1,
delta: 1,
repeat: 3,
}
``````
• [1, 2, 3, 5] corresponds to 2 sequences
``````Sequence {
start= 1,
delta: 1,
repeat: 2,
}

Sequence {
start= 5,
delta: 0,
repeat: 0,
}
``````

Now, I know how to do this the old way with while cycles and stuff.. I was experimenting a little bit around fold, reduce and I came up with an implementation (that doesn't work)

``````pub fn generate_sequences(from: Vec<u32>) -> Vec<Sequence> {
if from.is_empty() {
return Vec::new();
}
let mut sequences = Vec::new();
let mut last_sequence = Sequence::new(from, 0, 0);
let res = from.into_iter().fold(last_sequence, |mut seq, next| {
let delta = next - seq.start;
let res = match seq.delta {
0 => {
seq.delta = delta;
seq.repeat = 1;
seq
}
_ if seq.delta == delta => {
seq.repeat = seq.repeat + 1;
seq
}
_ => {
sequences.push(seq);
Sequence::new(next, 0, 0)
}
};
res
});
sequences.push(res);
sequences
}
}
``````

The implementation above doesn't work because the iter starts with the first item (so I count the first guy twice), so probably fold isn't the right operation here. I wonder if there is an idiomatic way of doing this in rust (my implementation is pretty ugly even if it would have worked )?

I would probably not implement this with iterators as I don't think it is possible to write an iterator solution that is easier to read than the loop solution.

1 Like

gotcha.. just for completeness I'll paste my "good old way" implementation.. not sure it's actually nicer though ``````    pub fn generate_sequences(from: Vec<u32>) -> Vec<Sequence> {
let mut sequences = Vec::new();
if from.is_empty() {
return sequences;
}
let mut i = 0;
let mut last_sequence = Sequence::new(from[i], 0, 0);

while i + 1 < from.len() {
let delta = from[i + 1] - from[i];
match last_sequence.delta {
0 => {
last_sequence.delta = delta;
last_sequence.repeat = 1;
}
_ if last_sequence.delta == delta => {
last_sequence.repeat = last_sequence.repeat + 1;
}
_ => {
sequences.push(last_sequence);
last_sequence = Sequence::new(from[i + 1], 0, 0)
}
}
i = i + 1;
}
sequences.push(last_sequence);
sequences
}
``````

I prefer this implementation:

``````#[derive(Debug)]
pub struct Sequence {
start: i32,
delta: i32,
repeat: usize,
}

fn find_next_sequence(data: &[i32]) -> Option<Sequence> {
if data.len() == 0 {
return None;
}
if data.len() == 1 {
return Some(Sequence {
start: data,
delta: 0,
repeat: 1,
});
}

let start = data;
let delta = data - data;

let mut next = data + delta;
let mut i = 2;
while i < data.len() && data[i] == next {
next += delta;
i += 1;
}

Some(Sequence {
start,
delta,
repeat: i,
})
}

pub fn generate_sequences(mut from: &[i32]) -> Vec<Sequence> {
let mut sequences = Vec::new();
while let Some(next) = find_next_sequence(from) {
from = &from[next.repeat..];
sequences.push(next);
}
sequences
}
``````
2 Likes

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.