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, 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 :slight_smile: )?

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 :smiley:

    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[0],
            delta: 0,
            repeat: 1,
        });
    }
    
    let start = data[0];
    let delta = data[1] - data[0];
    
    let mut next = data[1] + 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.