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();