To_lowercase() is temporary

I wrote a function that returns the most common words in the text.

fn find_most_frequent(text: &str) -> Vec<&str> {
    let txt: &str = &text.to_lowercase();
    let res: Vec<&str> = txt.split(|c: char| c.is_ascii_punctuation() || c.is_whitespace()).collect();
    let mut words: HashMap<&str, i16> = HashMap::new();
    for x in res {
        let count = words.entry(x).or_insert(0);
        *count += 1;
    }
    if words.contains_key("") {
        words.remove("");
    }
    let mx = words.values().max();
    let mut freq: Vec<&str> = vec![];
    for (k, v) in words.iter() {
        if Some(v) == mx {
            freq.push(k);
        }
    }
    freq.sort();
    freq
}

The function works as required. But can not return the result, because

let txt: &str = &text.to_lowercase();

is temporary and all variables that refer to it - cannot be returned

error[E0515]: cannot return value referencing temporary value
  --> src\main.rs:23:12
   |
5  |     let txt: &str = &text.to_lowercase();
   |                      ------------------- temporary value created here
...
23 |     return Cow::Owned(freq);
   |            ^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error: aborting due to previous error

How i can return result from this function?

Make the function return Vec<String> instead of Vec<&str>, and change that line to:

let txt: String = text.to_lowercase();

1 Like

Also, you can do this in a more functional style:

fn find_most_frequent(text: &str) -> Vec<String> {
    let text = text.to_lowercase();

    let words: HashMap<String, u16> = text
        .split(|c: char| c.is_ascii_punctuation() || c.is_whitespace())
        .filter(|s| !s.is_empty())
        .fold(HashMap::new(), |mut map, x| {
            let count = map.entry(x.to_string()).or_insert(0);
            *count += 1;
            map
        });

    let max: Option<u16> = words.values().max().copied();

    let mut freq = words.into_iter()
        .filter(|(_, v)| Some(*v) == max)
        .map(|(k, _)| k)
        .collect::<Vec<String>>();
    freq.sort();
    freq
}
2 Likes

Using Strings as the keys of the HashMap is not necessary; only the most frequent words need cloning. Hence the .to_string() can be moved from the HashMap into the Vec.

Thanks… I works…!