Write reduce function to reduce a vector to a value

fn reducer(v: &Vec<i32>, reduce_fn: fn(i32, i32) -> i32) -> I32 {
    let result = v.iter().reduce(|a, c| &reduce_fn(*a, *c));
    match result {
        Some(&v) => v,
            None => 0

fn add(x: i32, y: i32) -> i32 {

fn main() {
    let v:Vec<i32> = (0..10).collect();
    println!("{v:?} {}", reducer(&v, add));

I am not sure what I can do.

Here are the things that I want to do with this code:

  1. Work on the reference of a vector. Don't want to clone.
  2. Pass any function of the type (i32, i32) -> i32.
  3. Reduce the vector to an i32 value based on the function passed.
  1. You usually don't want to work on the reference of a vector, since borrowed slice, that is, &[u32], is strictly more powerful (it allows essentially everything that &Vec<u32> does).
  2. For that simple case, you can just insert .copied(), drop all the corresponding referencing/dereferencing, and everything will work - playground.
  3. If you were working with non-Copy types (and either don't want to use .cloned(), or the types are non-Clone either), you'd have to use fold instead of reduce and provide the default owned value explicitly.

you don't need vector specifically, reduce() is defined in Iterator. this will work for any iterators that yields i32:

fn reducer(v: impl Iterator<Item = i32>, reduce_fn: fn(i32, i32) -> i32) -> I32 {

then you can use the Fn trait bound, instead of a regular function pointer:

fn reducer(v: impl Iterator<Item = i32>, reduce_fn: impl Fn(i32, i32) -> i32) -> I32 {

this will accept Iterator<Item = i32> directly, but slice::iter() will give you an Iterator<Item = &i32>, you can use Iterator::cloned() to get an Iterator<Item = i32>, like this:

let v = &[1, 2, 3, 4];
let r = reducer(v.iter().cloned(), add);

to accept both Iterator<Item = i32> and Iterator<Item = &i32>, you'll need a trait that both &i32 and i32 implement. you can define a marker trait yourself, or there's a trait in the standard library with reflexivity, i.e. std::borrow::Borrow<i32>, (although it feels kind of wrong to abuse Borrow here, due to the semantical implications).

also, you can use IntoIterator in place of Iterator so the function can also accept a slice or array directly (no need to call iter() on it)

so the final form is something like this:

// marker trait for i32 and &i32
trait ToI32 { fn to_i32(&self) -> i32; }
impl ToI32 for i32 { fn to_i32(self) -> i32 { self } }
impl<'a> ToI32 for &'a i32 { fn to_i32(self) -> i32 { *self } }

// generic function
fn reducer<I, F>(values: I, f: F) -> i32
    I: IntoIterator,
    I::Iterm: ToI32,
    F: Fn(i32, i32) -> i32

// example usage
fn main() {
    let values = [1, 2, 3, 4];
    // slice
    reducer(&values[..], add);
    // array
    reducer(values, add);

    let values = vec![1, 2, 3, 4];
    // Iterator<Item = &i32>
    reducer(values.iter(), add);
    // Iterator<Item = i32>
    reducer(values.into_iter(), add);

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.