Reduce over an iterator of tuple

Hi,
I cannot work out how to satisfy the borrow checker here. Simplified example, but I want to iterate over a Vec of (x,y,z) to find the max of each of X, Y and Z - but then use the collection afterwards.

Using into_iter() works well - but I want to use .iter() and can't find the correct incantations of & !

fn main() {
    
    let coords = vec![(1, 2, 3), (1, 1, 2), (4, 1, 1)];
    // Find the max of x y and z 0 i.e. (4,2,3) from above
    
    // This fails to compile
    // Tried &(a,b,c) and (a,b,c) etc. but can't find the correct
    // comination, if one even exists
    let maxes = coords
        .iter()
        .reduce(|&(a, b, c), &(x, y, z)| (a.max(x), b.max(y), c.max(z)))
        .unwrap();
        
    // This compiles - but consumes the container
    let maxes = coords
        .into_iter()
        .reduce(|(a, b, c), (x, y, z)| (a.max(x), b.max(y), c.max(z)))
        .unwrap();
        
    // So I can't then do this
    for c in coords {
        println!("{:?}", c);
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0308]: mismatched types
  --> src/main.rs:11:42
   |
11 |         .reduce(|&(a, b, c), &(x, y, z)| (a.max(x), b.max(y), c.max(z)))
   |                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&({integer}, {integer}, {integer})`, found `({integer}, {integer}, {integer})`
   |
   = note: expected reference `&({integer}, {integer}, {integer})`
                  found tuple `({integer}, {integer}, {integer})`
help: consider borrowing here
   |
11 |         .reduce(|&(a, b, c), &(x, y, z)| &(a.max(x), b.max(y), c.max(z)))
   |                                          +

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (bin "playground") due to previous error

Copy the data while iterating.

     let maxes = coords
         .iter()
+        .copied()
+        .reduce(|(a, b, c), (x, y, z)| (a.max(x), b.max(y), c.max(z)))
-        .reduce(|&(a, b, c), &(x, y, z)| (a.max(x), b.max(y), c.max(z)))
         .unwrap();
2 Likes

If you had data which is not trivially copiable or cloneable, you could instead change your iterator item from &(Data, Data, Data) to (&Data, &Data, &Data).

The core issue is that reduce requires the output type to match the item type, but there is no single tuple storing the max-items-seen-so-far that you can return a reference to. However it's easy enough to

  • create an owned tuple as in my last reply
  • create a tuple of individually borrowed tuple members as in this reply
3 Likes

Thanks,
I was getting confused as i32s are trivially copyable and I though destructuring would do that but clearly this case needed something extra. Either of these work - thank you :slight_smile:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.