Understanding filter_map in rust

Viewed 13761

I am trying to get ages of all Person who has some second name. I was able to do it using filter and map separately as below, But I am wondering if we can use filter_map in rust.

But I am unable to figure it out.

struct Person {
    pub first_name: String,
    pub last_name: Option<String>,
    pub age: i32,
}


fn main() {
    let mut persons: Vec<Person> = Vec::new();
    persons.push(Person {
        first_name: "Asnim".to_string(),
        last_name: None,
        age: 1,
    });
    persons.push(Person {
        first_name: "Fahim".to_string(),
        last_name: Some("Ansari".to_string()),
        age: 2,
    });
    persons.push(Person {
        first_name: "Shahul".to_string(),
        last_name: None,
        age: 6,
    });
    persons.push(Person {
        first_name: "Mujeeb".to_string(),
        last_name: Some("Rahuman".to_string()),
        age: 6,
    });

    let ages_of_people_with_second_name_using_seperate_filter_map: Vec<i32> = persons
        .iter()
        .filter(|p| p.last_name.is_some())
        .map(|p| p.age)
        .collect();

    println!("{:?}", ages_of_people_with_second_name)
}
2 Answers

Yep. If you read the documentation for filter_map you'll realize how close you are. Could even use Option's map to help you out

Like:

let ages_of_people_with_second_name_using_seperate_filter_map: Vec<i32> = persons
        .iter()
        .filter_map(|p| p.last_name.map(|_| p.age))
        .collect();

Or a simpler way, using the match pattern:

let ages_of_people_with_second_name_using_seperate_filter_map: Vec<i32> = persons
        .iter()
        .filter_map(|p| match p.last_name { 
           Some(_) => Some(p.age),
           None => None
        })
        .collect();

But I am wondering if we can use filter_map in rust.

But I am unable to figure it out.

You can but it's not super useful here as the element you're filtering on and the element you're mapping are unrelated.

.filter_map(|p| p.last_name.as_ref().map(|_|, p.age))

So you're probably better off keeping the current version.

Usually the point of filter_map is to avoid the redundancy (and possibly cost) of something like

.filter(|p| p.last_name.is_some()).map(|p| p.last_name.unwrap())

in which case

.filter_map(|p| p.last_name)

is shorter, simpler, and more efficient.

Related