Home > Net >  Using fold together with enumerate to find max values in a selection of elements of a flattened vect
Using fold together with enumerate to find max values in a selection of elements of a flattened vect

Time:10-12

I am learning Rust and came upon a problem that I can easily solve by using nested loops with conditions. Unfortunately I fail miserably when trying to rewrite it using more idiomatic rust by the use of iterators and and things like fold, filter and flatten. I have a vector of vectors of structs. Each struct has an identifier and a value. For each possible identifier I want to find the maximum value and return everything in a new vec of max values. The code below works fine.

struct MyStruct {
    id: usize,
    value: usize,
}

fn main() {
    let vecvec_of_structs = vec![
        vec![
            MyStruct { id: 2, value: 1 },
            MyStruct { id: 1, value: 15 },
            MyStruct { id: 0, value: 31 },
        ],
        vec![
            MyStruct { id: 3, value: 10 },
            MyStruct { id: 4, value: 25 },
            MyStruct { id: 0, value: 150 },
            MyStruct { id: 2, value: 150 },
        ],
    ];
    let groups = 5;
    let mut max_values_by_id: Vec<usize> = vec![0; groups];

    // iterate over group_ids, in structs with respective group_id to find max value associated with it.
    for id in 0..groups {
        for vec_of_structs in &vecvec_of_structs {
            for s in vec_of_structs {
                if s.id == id {
                    if max_values_by_id[id] < s.value {
                        max_values_by_id[id] = s.value
                    };
                }
            }
        }
    }
    println!("{:?}", max_values_by_id);
}

Now I tried to rewrite it like the piece below, that I am stuck with and which doesn't work. I don't know how to combine the different pieces. Or maybe they are not supposed to fit together in the first place.

let max_delay: Vec<usize> = max_values_by_node
    .iter()
    .enumerate()
    .fold(0, |max_value, i| {
        &vecvec_of_structs
            .into_iter()
            .flatten()
            .filter(|e| e.id == i)
            .max_by_key(|e| e.value)
            .unwrap()
            .value
    })
    .collect();

CodePudding user response:

I would do something like this.

I start from the end: we want to collect five numbers.

For each of them considered as an id, we have have to iterate over all the structs: map() iter() flatten()

For each struct, we are only interested in the specific id, then we get its value: filter_map()

These values, if any, have to be folded.

    let max_delay: Vec<usize> = (0..5)
        .map(|i| {
            vecvec_of_structs
                .iter()
                .flatten()
                .filter_map(|s| if s.id == i { Some(s.value) } else { None })
                .fold(0, |acc, value| acc.max(value))
        })
        .collect();
  • Related