Using an Iterator to group structured data

Been getting better at using iterators to group data. The group_by function in itertools works well with a vector of primitive types. Had trouble doing it for a vector of custom types. Any way to do the following any simpler??

Sample data in:
(1, 0)
(2, 0)
(3, 0)
(4, 0)
(5, 1)
(6, 1)
(7, 1)
(8, 1)
(9, 1)

Data result. Accumulate the first and last .0 value for each .1 group
(1, 0, 4)
(5, 1, 9)

struct Item {
    data_p: i32,
    amt: i32,
}

impl PartialEq for Item {
    fn eq(&self, other: &Item) -> bool {
        self.amt == other.amt
    }
}

impl Eq for Item {}

fn main() {
    let mut lis: Vec<Item> = vec![];

    for i in 1..10 {
        lis.push(Item { data_p: i, amt: i / 5 });
    }

    for i in lis.iter() {
        println!("{:?}", (i.data_p, i.amt));
    }

    for i in my_group_by(&lis) {
        println!("{:?}", (i.0, i.1, i.2));
    }

}

fn my_group_by(lis: &Vec<Item>) -> Vec<(i32, i32, i32)> {
    let mut ans: Vec<(i32, i32, i32)> = vec![];
    if lis.len() > 0 {
        let mut iter = lis.iter().peekable();
        let mut first_of_group: bool = true;
        let mut acc = (0 as i32, 0 as i32, 0 as i32);
        loop {
            let i = iter.next().unwrap();
            if first_of_group {
                first_of_group = false;
                acc = (i.data_p, i.amt, acc.2);
            }
            if iter.peek() == None {
                acc.2 = i.data_p;
                ans.push(acc);
                break;
            }
            if i.amt != iter.peek().unwrap().amt {
                first_of_group = true;
                acc.2 = i.data_p;
                ans.push(acc);
                acc = (0, 0, 0);
            }
        }
    }
    ans
}
fn main() {
  let mut lis = vev![]; // usually inner type of vector is easily inferable by compiler
  ...
}

// always use &[T] over &Vec<T> . Former is more general, can be recursive by slicing, and sometimes can be stack allocated
fn my_group_by(lis: &[Item]) -> Vec<(i32, i32, i32)> {
  let mut ans = vec![];

  for item in lis {
    match ans.iter_mut().find(|&&mut (_, group, _)| group == item.amt) {
      Some(tuple) => tuple.2 = item.data_p,
      None => ans.push((item.data_p, item.amt, item.data_p)),
    }
  }

  ans
}
1 Like

Works great! Thanks for the suggestion.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.