PHP min() function replacement in Rust

I have good old, tested function in PHP to work with multi-local plural translations:

private function _plural(int $number, array $texts)
{
    $cases = [2, 0, 1, 1, 1, 2];

    return $texts[(($number % 100) > 4 && ($number % 100) < 20) ? 2 : $cases[min($number % 10, 5)]];
}

almost converted to Rust, but stuck with min function replacement:

fn plural(number: usize, strings: &[&str]) {
    let cases = [2, 0, 1, 1, 1, 2];
    strings[if (number % 100) > 4 && (number % 100) < 20 {
        2
    } else {
        cases[min(number % 10, 5)] // here
    }]
}

AI gives me following alternative:

fn min_in_array<T: Ord>(arr: &[T]) -> Option<&T> {
    arr.iter().min()
}

not sure it's correct, and yet nothing native in STD asset.

You probably want cmp::min(number % 10, 5).

2 Likes

Pretty sure you can just use std::cmp::min and it'll work as expected. This function is pretty codegolfy though, so making it more readable wouldn't be a bad idea.

3 Likes

This compiles. Don't know if you actually wanna deal with the string references or just clone them.

fn plural<'a>(number: usize, strings: &[&'a str]) -> &'a str {
    let cases = [2, 0, 1, 1, 1, 2];
    strings[if (number % 100) > 4 && (number % 100) < 20 {
        2
    } else {
        cases[std::cmp::min(number % 10, 5)]
    }]
}

EDIT
Sorry for the weird code highlighting. I don't know what is happening.

3 Likes

Thanks, guys!

just last question (even it's work) - is the lifetimes defined properly?

fn plural<'a>(number: usize, strings: &'a [&'a str]) -> &'a str {
    let cases = [2, 0, 1, 1, 1, 2];
    strings[if (number % 100) > 4 && (number % 100) < 20 {
        2
    } else {
        cases[std::cmp::min(number % 10, 5)]
    }]
}

Thanks for reply, just wrote same lifetimes construction :slight_smile:

I think it's better to keep strings referenced, without clone or the ownership taking. Maybe later I will make some crate to integrate this function everywhere.

Mine is slightly different from yours. I only put 'a on the &'a str but not on the slice &[&'a str] in the second argument.

1 Like

ah, really!

p.s. also shortened this function to

fn plural<'a>(n: usize, s: &[&'a str]) -> &'a str {
    s[if (n % 100) > 4 && (n % 100) < 20 {
        2
    } else {
        [2, 0, 1, 1, 1, 2][std::cmp::min(n % 10, 5)]
    }]
}

If somebody want the subject to work with this function

let result = plural(total, &["match", "matches", "matches"]); // en version

p.p.s sometimes I miss ?/: sugar for if/else in Rust..

p.p.p.s just created new crate.

You can also use the method min from the Ord trait:

(n % 10).min(5) 
// or 5.min(n % 10)
// or even usize::min(n % 10, 5)

Honestly I believe that std::cmp::min/max only exist because Ord didn’t have those methods before Rust 1.21.

1 Like

Thank you, replaced with usize - just not sure about performance (if it has any sense here)

There’s zero difference. It’s just a matter of preference.

2 Likes