Shorter way to convert Vec<Result<Option<T>, E>> to Result<Vec<T>, E>

I have the following code converting from Vec<Result<Option<T>, E>> to Result<Vec<T>, E> but I’m wondering if there’s something I don’t know about iterators that could simplify it even more/make the code more concise.

fn clean<T, E>(data: Vec<Result<Option<T>, E>>) -> Result<Vec<T>, E> {
    data.into_iter()
        .filter_map(|i| match i {
            Ok(Some(a)) => Some(Ok(a)),
            Ok(None) => None,
            Err(e) => Some(Err(e)),
        })
        .collect()
}

I was able to reduce it to this, but find the first example better since it does not have any .unwrap():

fn clean<T, E>(data: Vec<Result<Option<T>, E>>) -> Result<Vec<T>, E> {
    data.into_iter()
        .filter_map(|i| match i {
            Ok(None) => None,
            _ => Some(i.map(|i| i.unwrap())),
        })
        .collect()
}

>Solution :

I’m not sure of your definition of "cleaner" but you can make it a lot shorter by using transpose:

fn clean<T, E>(data: Vec<Result<Option<T>, E>>) -> Result<Vec<T>, E> {
    data.into_iter().filter_map(|i| i.transpose()).collect()
}

Or maybe you’d consider the point-free version cleaner:

fn clean<T, E>(data: Vec<Result<Option<T>, E>>) -> Result<Vec<T>, E> {
    data.into_iter().filter_map(Result::transpose).collect()
}

Leave a Reply