0

I have a nested Vec structure where I need to convert the deepest Vec into a tuple. Consider the following example:

fn main() {
    let input = vec![vec![vec![vec![1.0, 2.0]]]];
    let output: Vec<Vec<Vec<(f64, f64)>>> = input
        .iter()
        .map(|r1| {
            r1.iter()
                .map(|r2| r2.iter().map(|r3| (r3[0], r3[1])).collect())
                .collect()
        })
        .collect();
}

I make the assumption that there are at least two values in the deepest vector, but if there aren't, then this code will fail. I'd like to have main return an error to indicate this, but because the indexing is in the iterator chain, I cannot simply use ? or return an error.

I'd like to not turn this whole thing into for loops. Assuming this, what are my options and what is idiomatic?

Listerone
  • 1,381
  • 1
  • 11
  • 25
  • 1
    Did you read this? https://doc.rust-lang.org/rust-by-example/error/iter_result.html#fail-the-entire-operation-with-collect – SOFe Aug 26 '19 at 05:26
  • a vec of vec of vec is the worst thing to do, also call the 3 stars programmers in C. you should use ndarray – Stargateur Aug 26 '19 at 16:05

1 Answers1

2

Result<FromIterator<Item = T>, E> implements FromIterator<Result<T, E>>. You can collect an iterator of Results into a Result of a collection and use ? on the Result.

Moreover, since it is FromIterator, you can recursively collect the result, directly collecting an iterator of Results into a Result of Vec.

fn main() -> Result<(), &'static str> {
    let input = vec![vec![vec![vec![1.0, 2.0]]]];
    let output: Vec<Vec<Vec<(f64, f64)>>> = input
        .iter()
        .map(|r1| {
            r1.iter()
                .map(|r2| {
                    r2.iter()
                        .map(|r3| {
                            if r3.len() >= 2 {
                                Ok((r3[0], r3[1]))
                            } else {
                                Err("Bad")
                            }
                        })
                        .collect::<Result<Vec<_>, &str>>()
                })
                .collect::<Result<Vec<_>, &str>>()
        })
        .collect::<Result<Vec<_>, &str>>()?;

    Ok(())
}

playground

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
SOFe
  • 7,867
  • 4
  • 33
  • 61
  • By the way, after I passed this to `rustfmt`, it looks even more spaghetti than using three for loops. – SOFe Aug 26 '19 at 13:18