Find the shortest string in a vector


#1

Is there a better way to do this? Could I use an iterator to achieve the same? I also tried using sort_by but I have to clone the names if I do that because names is not mutable.

Would love to see some other examples of how to do this. Also I don’t care about alphabetical order, but would be cool to see how to return for example “a” before “z”.

    fn get_shortest<'a>(names: &Vec<&'a str>) -> Option<&'a str> {
        if names.len() == 0 {
            return None;
        }
        
        let mut n = names[0];
        for name in names {
            if name.len() < n.len() {
                n = name;
            }
        }
        return Some(n);
    }
    
    fn main() {
        let names:Vec<&str> = vec!["Dave", "Latoya", "Ben", "Jake"];
        
        println!("name: {:?}", &names);
        
        match get_shortest(&names) {
            Some(name) => {
                println!("Shortest: {}!", name);
            },
            None => {
                println!("No result!");
            }
        };        
    }

#3

Any time you have a list of something, and you want a single something, you
can use fold:

    let name = names.iter().fold(names[0], |acc, &item| {
        if item.len() < acc.len() {
            item
        } else {
            acc
        }
    });

    return Some(name);

#4

Awesome thanks! I didn’t really understand the docs…

Performs a fold operation over the entire iterator, returning the eventual state at the end of the iteration.

I feel like reduce would be easier to understand, and the example builds a sum which doesn’t really illustrate what it’s actually useful for…

let a = [1, 2, 3, 4, 5];
assert!(a.iter().fold(0, |acc, &item| acc + item) == 15);

#5

.min_by() on Iterator is the perfect tool for this. Unfortunately it is unstable. But this is how it works:

(Playpen link)

#![feature(core)]
fn main() {
    let strings = ["z", "abc", "b", "a"];
    let min = strings.iter().min_by(|&&s| (s.len(), s));
    println!("{:?}", min);   // OUTPUT: Some("a")
}

It uses a key. I used the key (s.len(), s) so that it compares by minimal length first, then the string.

I’m sure this method will appear in a stable release eventually.


#7

By the way, write code like this to get rust syntax hilighting on this forum.

```rust
let mut foo = 1;
```
let mut foo = 1;

#9

It still compiles with one yeah. I’ll annotate the types

// strings is a fixed length array of &str, length four:  [&str; 4]
// element type is &str.
let strings: [&str; 4] = ["z", "abc", "b", "a"];
// .iter() returns the slice iterator std::slice::Iter<&str>
// which iterates by reference, so the iterator element type is `&&str`.
let min = strings.iter()
// min_by passes a *reference* to the iterator element.
// Reference to the iterator element is &&&str.  (!!)
// use `&&s` in the signature to wrap off two layers of &'s!

// The variable `s` in the closure has type &str.
       .min_by(|&&s| (s.len(), s));

See the signature of the .min_by() method


#10

Yeah, iterator’s docs are kinda hard, due to the implementation. And it depends on which language background you come from: some call it reduce, some fold.

I mean, a sum is generally the first thing that you learn when using fold. But yes, in general, more stuff would be good :smile:


#11

I was surprised the Iter docs didn’t mention “reduce” as another name for “fold”, so I added a line to the docs: #25144.


#12

Maybe we can add a bigger explanation of what fold does, something newbie friendly maybe a bit like this from fold_results. (Don’t know how well that explanation works in practice).


#13

I’m not sure the iter docs are the right place for this. Maybe we should link to a good explanation (e.g. the iterators chapter in the book)?

Sadly, the book has only a few paragraphs about folding. A few days ago I read “A Journey into Iterators”. Another really good article about folding and function list operations in general is this chapter from Learn you a Haskell, but it was obviously written with Haskell in mind (the illustrations are universal though!).


#14

@killercup You know what would be cool… 101 C# LINQ samples in Rust…

Swift


#15

Clojure