隱私權政策

搜尋此網誌

技術提供:Blogger.

關於我自己

我的相片
目前從事軟體相關行業,喜歡閱讀、健身、喝調酒。習慣把遇到的問題記下來,每天做一些整理方便自己以後查。 Python、Rust、Kotlin等程式語言皆為自學,目前比較著重在Rust語言,歡迎一起討論。

2023年11月15日 星期三

Rust 迭代max_by、max_by_key和min_by、min_by_key - 獲得資料最大值與最小值


獲得最大值最小值有三種方法

一個是max、min

一個是max_by、min_by

最後則是max_by_key、min_by_key

這篇[1]有提到max和min

而本文則是會比較三者差別以及介紹_by和_by_key


先比較三者差別,以最大值舉例

    fn max(self) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: Ord,
    fn max_by<F>(self, compare: F) -> Option<Self::Item>
    where
        Self: Sized,
        F: FnMut(&Self::Item, &Self::Item) -> Ordering,

    fn max_by_key<B, F>(self, f: F) -> Option<Self::Item>
    where
        B: Ord,
        Self: Sized,
        F: FnMut(&Self::Item) -> B,

三種都是被歸類在iter下

並且回傳都是Option,裡面包含最大值

不同的是max[2]為一種默認行為

max_by[3]需要使用一個閉包,並且對兩個元素引用

max_by_key[4]則是一樣會使用閉包,但只對一個元素引用

min[5]min_by[6]min_by_key[7]同理


比較

以一個程式比較三種打法

    let numbers = vec![3, 5, 2, 1, 9, 12, 6];
    println!("max: {:?}", numbers.iter().max());
    println!("max_by: {:?}", numbers.iter().max_by(|&x, &y| x.cmp(y)));
    println!("max_by_key: {:?}", numbers.iter().max_by_key(|&x| x));
    println!("min: {:?}", numbers.iter().min());
    println!("min_by: {:?}", numbers.iter().min_by(|&x, &y| x.cmp(y)));
    println!("min_by_key: {:?}", numbers.iter().min_by_key(|&x| x));
max: Some(12) max_by: Some(12) max_by_key: Some(12) min: Some(1) min_by: Some(1) min_by_key: Some(1)

max具有直接默認的特性

max_by需要使用兩個元素,並且比較最大值

max_by_key則是相對直觀,使用一個元素就可以比較最大值

以我目前認知來說,大概是這樣




例子

在大多數情況下,max_by和max_by_key是可以共通的

國外也蠻多人在討論兩個哪邊有"明顯"的不一樣

在我看來,就只是容不容易閱讀的差別

但reddit的這篇文章[8]有提出生命週期的問題

我覺得很有趣,就直接把程式碼放上來了

fn main() {
    let items = vec!["zaa".to_string(), "ybb".to_string(), "xbc".to_string()];

    // get the max by substring from the 2nd character to the end

    // works
    // let max = items.into_iter().max_by(|s1, s2| s1[1..].cmp(&s2[1..]));

    // error: lifetime may not live long enough
    let max = items.into_iter().max_by_key(|s| &s[1..]);

    println!("max: {:?}", max);

}error: lifetime may not live long enough --> src\main.rs:10:48 | 10 | let max = items.into_iter().max_by_key(|s| &s[1..]); | -- ^^^^^^^ returning this value
requires that `'1` must outlive `'2` || | |return type of closure is &'2 str | has type `&'1 String`

會發現上面的let max可以正常動作

但下面let max則會err

錯誤訊息為生命週期不夠長

Rust編譯器無法判定閉包和String引用哪個生命週期長

只要把into_iter()改成引用iter()就可以了

但生命週期的問題真的太頭痛

到現在也還沒有搞懂

哪天搞懂再寫一篇


參考資料

[1] https://lageeblog.blogspot.com/2023/11/rust-maxmin.html

[2] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max

[3] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by

[4] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.max_by_key

[5] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min

[6] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by

[7] https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.min_by_key

[8] https://www.reddit.com/r/rust/comments/nh5iup/what_is_the_intention_of_the_max_by_iterator/






0 comments:

張貼留言