`HashMap` values to slice or iterator

I was hoping that following would just compile.

use std::collections::HashMap;

fn sum(vals: &[usize]) -> usize {
    let mut s = 0usize;
    for v in vals.iter() {
        s += v;
    }
    s
}

fn main() {
    let cs: HashMap<&str, usize> = HashMap::from([("a", 1), ("b", 4)]);
    let ans = sum(cs.values().collect()); // hoping it would work
    println!("Ans is {ans}");
}

I don't want to allocate memory to be able to use sum. What is the best strategy here so that sum can be used by any iterator e.g. reference to Vec<usize>, HashSet<usize> and values of HashMap<_, usize>?

take iterators as argument directly

fn sum<I>(vals: I) -> usize where I: IntoIterator<Item = usize> {
    todo!()
}
fn main() {
    let cs: HashMap<&str, usize> = HashMap::from([("a", 1), ("b", 4)]);
    let ans = sum(cs.values().copied()); 
    println!("Ans is {ans}");
}

or better yet, just use Iterator::sum

fn main() {
    let cs: HashMap<&str, usize> = HashMap::from([("a", 1), ("b", 4)]);
    let ans: usize =cs.values().sum();
    println!("Ans is {ans}");
}
6 Likes

You can't go from one data structure (HashMap) to another using the iterators interface without allocating. That's why there's no implementation to "collect" into a slice. You can only make sum generic over IntoIterator:

use std::collections::HashMap;

fn sum(vals: impl IntoIterator<Item = usize>) -> usize {
    let mut s = 0usize;
    for v in vals.into_iter() {
        s += v;
    }
    s
}

fn main() {
    let cs: HashMap<&str, usize> = HashMap::from([("a", 1), ("b", 4)]);
    let ans = sum(cs.values().copied().collect::<Vec<_>>()); // hoping it would work
    println!("Ans is {ans}");
}
1 Like

Since Iterator implements IntoIterator, you do not need the collect on that example.

2 Likes

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.