Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a non-recursive calculation of factorial using iterators and ranges?

I ran into a Rustlings exercise that keeps bugging me:

pub fn factorial(num: u64) -> u64 {
    // Complete this function to return factorial of num
    // Do not use:
    // - return
    // For extra fun don't use:
    // - imperative style loops (for, while)
    // - additional variables
    // For the most fun don't use:
    // - recursion
    // Execute `rustlings hint iterators4` for hints.
}

A hint to solution tells me...

In an imperative language you might write a for loop to iterate through multiply the values into a mutable variable. Or you might write code more functionally with recursion and a match clause. But you can also use ranges and iterators to solve this in rust.

I tried this approach, but I am missing something:

if num > 1 {
    (2..=num).map(|n| n * ( n - 1 ) ??? ).???
} else {
    1
}

Do I have to use something like .take_while instead of if?

like image 501
dombo Avatar asked Mar 24 '20 16:03

dombo


Video Answer


2 Answers

The factorial is defined as the product of all the numbers from a starting number down to 1. We use that definition and Iterator::product:

fn factorial(num: u64) -> u64 {
    (1..=num).product()
}

If you look at the implementation of Product for the integers, you'll see that it uses Iterator::fold under the hood:

impl Product for $a {
    fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
        iter.fold($one, Mul::mul)
    }
}

You could hard-code this yourself:

fn factorial(num: u64) -> u64 {
    (1..=num).fold(1, |acc, v| acc * v)
}

See also:

  • How to sum the values in an array, slice, or Vec in Rust?
  • How do I sum a vector using fold?
like image 57
Shepmaster Avatar answered Oct 17 '22 07:10

Shepmaster


Although using .product() or .fold() is probably the best answer, you can also use .for_each().

fn factorial(num: u64) -> u64 {
    let mut x = 1;
    (1..=num).for_each(|i| x *= i);
    x
}
like image 22
Brighton Sikarskie Avatar answered Oct 17 '22 05:10

Brighton Sikarskie