Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sum the values in an array, slice, or Vec in Rust?

Tags:

rust

Editor's note: This question's example is from a version of Rust prior to 1.0 and references types and methods no longer found in Rust. The answers still contain valuable information.

The following code

let mut numbers = new_serial.as_bytes().iter().map(|&x| (x - 48));
let sum = numbers.sum(); 

results in the following error:

std::iter::Map<,&u8,u8,std::slice::Items<,u8>>` does not implement any method in scope named `sum`

What must I do to sum an array of bytes?

The following works:

for byte in new_serial.as_bytes().iter() {
    sum = sum + (byte - 48);
}
like image 904
rogergl Avatar asked Apr 16 '14 05:04

rogergl


People also ask

What is Rust Vec?

The Vec type allows to access values by index, because it implements the Index trait. An example will be more explicit: let v = vec![ 0, 2, 4, 6]; println!("

How do you initialize VEC in Rust?

In Rust, there are several ways to initialize a vector. In order to initialize a vector via the new() method call, we use the double colon operator: let mut vec = Vec::new();


2 Answers

Iterator::sum was stabilized in Rust 1.11.0. You can get an iterator from your array/slice/Vec and then use sum:

fn main() {
    let a = [1, 2, 3, 4, 5];
    let sum: u8 = a.iter().sum();
    println!("the total sum is: {}", sum);
}

Of special note is that you need to specify the type to sum into (sum: u8) as the method allows for multiple implementations. See Why can't Rust infer the resulting type of Iterator::sum? for more information.


Applied to your original example:

let new_serial = "01234";
let sum: u8 = new_serial.as_bytes().iter().map(|&x| x - 48).sum();
println!("{}", sum);

As an aside, it's likely more clear if you use b'0' instead of 48.

like image 119
Chris Morgan Avatar answered Oct 16 '22 18:10

Chris Morgan


If performance is important, consider using an implementation that helps the compiler at producing SIMD instructions.

For example, for f32, using 16 lanes (total of 512 bits):

use std::convert::TryInto;

const LANES: usize = 16;

pub fn nonsimd_sum(values: &[f32]) -> f32 {
    let chunks = values.chunks_exact(LANES);
    let remainder = chunks.remainder();

    let sum = chunks.fold([0.0f32; LANES], |mut acc, chunk| {
        let chunk: [f32; LANES] = chunk.try_into().unwrap();
        for i in 0..LANES {
            acc[i] += chunk[i];
        }
        acc
    });

    let remainder: f32 = remainder.iter().copied().sum();

    let mut reduced = 0.0f32;
    for i in 0..LANES {
        reduced += sum[i];
    }
    reduced + remainder
}

pub fn naive_sum(values: &[f32]) -> f32 {
    values.iter().sum()
}

for

let values = (0..513).map(|x| x as f32).collect::<Vec<_>>();

the above is 10x faster than values.iter().sum() on my computer:

nonsimd_sum             time:   [77.341 ns 77.773 ns 78.378 ns]
naive_sum               time:   [739.97 ns 740.48 ns 740.97 ns]

and ~10% slower than using packed_simd2 (but it does not require nightly).

like image 43
Jorge Leitao Avatar answered Oct 16 '22 19:10

Jorge Leitao