How to get min, max, min_index, max_index?

Hi All,

I have a Vec<f32> and I want to get the sum, max, min, max_index and min_index. I can do all this with Itertools minmax() and position_minmax() but that needs three pass. Other suggestion is to use std like max(), position() and min() but that also needs more than 1 pass. Hence, I wrote the below code,

fn main() {
    let items = [20.0, 4.1, 1.1, 17.2, -33.7, 21.6];

    let (max, max_index, min, min_index, sum) = items
                     .iter()
                     .enumerate()
                     .fold((items[0], 0, items[0], 0, 0.0), |acc, (index,&x)| {
                        let max;
                        let min;
                        let max_index;
                        let min_index;
                        let sum;
                        
                        if x > acc.0 {
                            max = x;
                            max_index = index;
                        } else {
                            max = acc.0;
                            max_index = acc.1;
                        }
                        
                        
                        if x < acc.2 {
                            min = x;
                            min_index = index;
                        } else {
                            min = acc.2;
                            min_index = acc.3;
                        }
                        
                        sum = acc.4 + x;
                        
                        (max, max_index, min, min_index, sum)
                     });
    println!("{}, {}", max, max_index);
    println!("{}, {}", min, min_index);
    println!("{}, {}", sum, sum as f32 / items.len() as f32);
}

Is it possible to write this in idiomatic way?

1 Like

You code looks fine, but personally I think a for loop is more readable than fold when you have multiple accumulators:

let mut max = items[0];
let mut min = items[0];
let mut max_index = 0;
let mut min_index = 0;
let mut sum = 0.0;

for (index, &x) in items.iter().enumerate() {
    if x > max {
        max = x;
        max_index = index;
    }
    if x < min {
        min = x;
        min_index = index;
    }
    sum += x;
}
2 Likes

maybe a generic version:

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct MaxMin<T> {
    max: (T, usize),
    min: (T, usize),
}

pub fn find_max_min<T: std::cmp::PartialOrd + Copy>(slice: &[T]) -> MaxMin<T> {
    let mut max = &slice[0];
    let mut min = &slice[0];

    let mut max_pos: usize = 0;
    let mut min_pos: usize = 0;

    for index in 1..slice.len() {
        if slice[index] < *min { min = &slice[index]; min_pos = index;}
        if slice[index] > *max { max = &slice[index]; max_pos = index;}
    }

    MaxMin{max: (*max, max_pos), min: (*min, min_pos)}
}

fn main() {
    let items = [320.0, 4.1, 1.1, 17.2, -33.7, 21.6];

    let max_min = find_max_min(&items);

    println!("max_min: {:?}", max_min);
}

2 Likes

Thanks @mbrubeck and @elsuizo for suggestions. I was hoping there will be a crate which can give the statistics summary like R.

Anyway, I can live with this now :slight_smile: Thanks again.

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.