隱私權政策

搜尋此網誌

技術提供:Blogger.

關於我自己

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

2023年11月18日 星期六

Rust 迭代take - 控制迭代次數


take具有控制迭代器迭代次數的功能

被歸類在iter


take

文件[1]這樣解釋take

創造一個迭代器,迭代前n個元素

如果原本迭代器比較少則會直接迭代完

    fn take(self, n: usize) -> Take<Self>
    where
        Self: Sized,

self為一個迭代器

n為迭代次數

回傳一個Take迭代器[2]

Take 也是一個迭代器

於Struct std::iter::Take

用處為回傳迭代器前n個元素


舉個例子

假設有個數組,只想要取其前五個

可以這樣打

    let numbers = vec![1, 5, 6, 7, 9, 3, 4, 5];
    let res = numbers.iter().take(5).collect::<Vec<_>>();
    println!("{:?}", res);
[1, 5, 6, 7, 9]

透過第二行將數組放入迭代器中

並使用take取出前五個


而如果輸入數字超出數組範圍

也不會有Panic

最多就是輸出數組全部

    let numbers = vec![1, 5, 6, 7, 9, 3, 4, 5];
    let res = numbers.iter().take(10).collect::<Vec<_>>();
    println!("{:?}", res);
[1, 5, 6, 7, 9, 3, 4, 5]


舉一個比較複雜一點的例子

假設銀行有使用者姓名還有他們資產總額

希望取出前三個存款最多的人,但不能有負債

使用take為其中一種解法

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct User {
    name: String,
    balance: i32,
}

fn main() {
    let mut users = vec![
        User {
            name: "Alice".to_string(),
            balance: -100,
        },
        User {
            name: "Bob".to_string(),
            balance: 150,
        },
        User {
            name: "Charlie".to_string(),
            balance: -130,
        },
        User {
            name: "David".to_string(),
            balance: -80,
        },
        User {
            name: "Eva".to_string(),
            balance: 200,
        },
        User {
            name: "Frank".to_string(),
            balance: -20,
        },
    ];
    users.sort_by(|a, b| b.balance.cmp(&a.balance));
    let res: Vec<_> = users.iter().filter(|x| x.balance > 0).take(3).collect();
    println!("{:#?}", res);
}

users共有六個人,以及他們的金額

先透過sort_by[3]從大到小排列

將其放入數組,透過filter[4]判斷其資產是正數還是負數

並且取前三個

只有兩個人資產是正數

因此結果為

    [
        User {
            name: "Eva",
            balance: 200,
        },
        User {
            name: "Bob",
            balance: 150,
        },
    ]

實際題目

寫這篇是因為CodeWars有一題我覺得蠻有趣的

Training on Find The Parity Outlier | Codewars

難度是6kyu

題目為

You are given an array (which will have a length of at least 3, but could be very large) containing integers. The array is either entirely comprised of odd integers or entirely comprised of even integers except for a single integer N. Write a method that takes the array as an argument and returns this "outlier" N.

Examples

[2, 4, 0, 100, 4, 11, 2602, 36] -->  11 (the only odd number)

[160, 3, 1719, 19, 11, 13, -21] --> 160 (the only even number)

意思有一個數組,裡面幾乎都是偶數會奇數

只會有一個數跟其他數值不一樣

當整個數值是偶數時,有一個奇數混在裡面

當整個數值是奇數時,有一個偶數混在裡面

要找出裡面那個混在裡面的小兔崽子

fn find_outlier(values: &[i32]) -> i32 {}

可以透過這個測試測看看程式

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn basic_test() {
        let t1 = [2,6,8,-10,3];
        let t2 = [206847684,1056521,7,17,1901,21104421,7,1,35521,1,7781];
        let t3 = [std::i32::MAX, 0, 1];
        assert_eq!(3, find_outlier(&t1));
        assert_eq!(206847684, find_outlier(&t2));
        assert_eq!(0, find_outlier(&t3));
    }
}



解答:

fn find_outlier(values: &[i32]) -> i32 {
    let odd_or_even = match values
        .iter()
        .take(3)
        .map(|x| x.abs() % 2).sum::<i32>() < 2 {
            true => 0,
            false => 1,
        };
    *values.iter().find(|x| x.abs() % 2 != odd_or_even).unwrap()
}

先使用take(3)判斷前面三個數值是偶數還是奇數

並記錄在odd_or_even

之後透過find找出跟前三個數值不同的數字

最後unwrap輸出



參考資料

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

[2] https://doc.rust-lang.org/std/iter/struct.Take.html

[3] https://lageeblog.blogspot.com/2023/11/rust-sortsortby.html

[4] https://lageeblog.blogspot.com/2023/10/rust-filter.html

[5] https://www.codewars.com/kata/5526fc09a1bbd946250002dc/train/rust


0 comments:

張貼留言