Jon Wolski
Jon Wolski

Reputation: 2833

How can I sum a range of numbers in Rust?

I want to write a function to sum the numbers from zero to n. (Ideally, this would be generic over all numbers, but I will settle for i32).

mod squares {

    pub fn sum_from_zero( n: i32) -> i32 {
        [0 .. n].fold(0, |a, b| a + b)
    }
}

#[test]
fn test_sum_from_zero() {
    assert_eq!(15, squares::sum_from_zero(5));
}

I get the following compiler error:

src/lib.rs:5:18: 5:22 error: no method named `fold` found for type `[std::ops::Range<i32>; 1]` in the current scope
src/lib.rs:5         [0 .. n].fold(0, |a, b| a + b)
                              ^~~~
src/lib.rs:5:18: 5:22 note: the method `fold` exists but the following trait bounds were not satisfied: `[std::ops::Range<i32>; 1] : std::iter::Iterator`, `[std::ops::Range<i32>] : std::iter::Iterator`

I've also tried this with sum():

mod squares {

    pub fn sum_from_zero( n: i32) -> i32 {
        [0 .. n].sum()
    }
}

#[test]
fn test_sum_from_zero() {
    assert_eq!(15, squares::sum_from_zero(5));
}

And got the following compiler error:

src/lib.rs:5:18: 5:21 error: no method named `sum` found for type `[std::ops::Range<i32>; 1]` in the current scope
src/lib.rs:5         [0 .. n].sum()
                              ^~~
src/lib.rs:5:18: 5:21 note: the method `sum` exists but the following trait bounds were not satisfied: `[std::ops::Range<i32>; 1] : std::iter::Iterator`, `[std::ops::Range<i32>] : std::iter::Iterator`
src/lib.rs:5:18: 5:21 error: no method named `sum` found for type `[std::ops::Range<i32>; 1]` in the current scope
src/lib.rs:5         [0 .. n].sum()
                              ^~~
src/lib.rs:5:18: 5:21 note: the method `sum` exists but the following trait bounds were not satisfied: `[std::ops::Range<i32>; 1] : std::iter::Iterator`, `[std::ops::Range<i32>] : std::iter::Iterator`

Do I have to declare explicit bounds/traits?

Upvotes: 11

Views: 12471

Answers (5)

Richard Neumann
Richard Neumann

Reputation: 454

All of the answers ignore the fact, that the OP wants to sum i32, not u32 from 0 to n. This implies that there may also be negative sums involved (0 + -1 + -2 + ... + n). Hence, I propose:

fn summation(n: i32) -> i32 {
    if n < 0 {
        (n..0).sum()
    } else {
        (0..=n).sum()
    }
}

Upvotes: 0

Uwumilia
Uwumilia

Reputation: 21

I recommend to use that the sum you're looking for is equal to n*(n+1)/2; assuming that there is no reason against using that, because you did not mention any in your question.

Upvotes: 2

Anshul
Anshul

Reputation: 106

Other people have given valid answers, but I assume the following is the simplest way to do it.

fn summation(n: i32) -> i32 {
    (0..=n).sum()
}

#[cfg(test)]
mod tests {
    use super::summation;

    #[test]
    fn basic_tests() {
        assert_eq!(summation(1), 1);
        assert_eq!(summation(8), 36);
        assert_eq!(summation(22), 253);
        assert_eq!(summation(100), 5050);
        assert_eq!(summation(213), 22791);
    }
}

Upvotes: 3

RΣAL
RΣAL

Reputation: 11

You can use the Iterator trait, which includes the sum method, to sum a range of numbers. Here's an example implementation:

mod squares {

    pub fn sum_from_zero(n: i32) -> i32 {
        (0..=n).into_iter().sum()
    }
}

Upvotes: 1

Arjan
Arjan

Reputation: 21505

The problem is that you are creating an array of ranges (square brackets) but you just wanted the range (on which fold is defined).

Another thing is that range syntax (..) is only inclusive of the lower bound. It's exclusive of the upper bound so you have to iterate up to n+1 to get the desired result.

mod squares {

    pub fn sum_from_zero( n: i32) -> i32 {
        (0 .. n+1).fold(0, |a, b| a + b)
    }
}

#[test]
fn test_sum_from_zero() {
    assert_eq!(15, squares::sum_from_zero(5));
}

Upvotes: 18

Related Questions