3

I'm trying to make a code that returns the mode of a list of given numbers. Here's the code :

 use std::collections::HashMap;

 fn mode (vector: &Vec<i32>) -> Vec<&&i32> {
    let mut occurrences = HashMap::new();
    let mut n= Vec::new(); 
    let mut mode = Vec::new(); 

    for i in vector {
    let j= occurrences.entry(i).or_insert(0); 
        *j+=1;
    }

    for (num, occ) in occurrences.clone().iter() {

        if occ> n[0] {
            n.clear();
            mode.clear();

            n.push(occ);
            mode.push(num);
        } else if occ== n[0] {
                mode.push(num);             
            }
        }

    mode
}

fn main () {
    let mut numbers: Vec<i32>= vec![1,5,2,2,5,3];    // 2 and 5 are the mode
    numbers.sort();
    

    println!("the mode is {:?}:", mode(&numbers));
}

I used a vector for the mode since a dataset could be multimodal. Anyway, I'm getting the following error:

error[E0515]: cannot return value referencing temporary value
 --> src/main.rs:26:5
  |
13 |     for (num, occ) in occurrences.clone().iter() {
  |                       ------------------- temporary value created here
...
26 |     mode
  |     ^^^^ returns a value referencing data owned by the current function
3
  • I think there are an issue in your algo thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0' playground Commented Oct 31, 2021 at 11:15
  • And i m not sure to understand what mode must do and what mode must return Commented Oct 31, 2021 at 11:18
  • Is it a requirement that mode return Vec<&&i32>? Could this be changed? Commented Oct 31, 2021 at 11:19

1 Answer 1

3

When you return from the current function, any owned values are destroyed (other than the ones being returned from the function), and any data referencing that destroyed data therefore cannot be returned, e.g.:

fn example() -> &str {
  let s = String::from("hello");  // owned data
  &s  // error: returns a value referencing data owned by the current function

  // you can imagine this is added by the compiler
  drop(s);
} 

The issue you have comes from iter(). iter() returns an iterator of shared references:

let values: Vec<i32> = vec![1, 2, 3];
for i in values.iter() {
  // i is a &i32
}

for i in values {
  // i is an i32
}

So when you call occurrences.clone().iter() you're creating a temporary value (via clone()) which is owned by the current function, then iterating over that data via shared reference. When you destructure the tuple in (num, occ), these are also shared references.

Because you later call mode.push(num), Rust realizes that mode has the type Vec<&i32>. However, there is an implicit lifetime here. The lifetime of num is essentially the lifetime of the current function (let's call that 'a), so the full type of mode is Vec<&'a i32>.

Because of that, you can't return it from the current function.

To fix

Removing iter() should work, since then you will be iterating over owned values. You might also find that you can remove .clone() too, I haven't looked too closely but it seems like it's redundant.

A couple of other points while you're here:

  • It's rare to interact with &Vec<Foo>, instead it's much more usual to use slices: &[Foo]. They're more general, and in almost all cases more performant (you can still pass your data in like: &numbers)
  • Check out clippy, it has a bunch of linter rules that can catch a bunch of errors much earlier, and usually does a good job explaining them: https://github.com/rust-lang/rust-clippy
Sign up to request clarification or add additional context in comments.

1 Comment

I also had to change the 5th line with let mut n= vec![0]; since i was trying to index an empty vector. As @Vaillant Etienne suggested

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.