隱私權政策

搜尋此網誌

技術提供:Blogger.

關於我自己

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

2023年11月24日 星期五

Rust 迭代sum和product概述 - 求和以及求積


這篇講求和以及求積

sum 為迭代器中所有數值加起來

product 為迭代器中所有數值乘起來

這兩個算是比較簡單可以實現和以及積的方法


sum

文件[1]這樣提到了sum

將迭代器所有元素加起來

    fn sum<S>(self) -> S
    where
        Self: Sized,
        S: Sum<Self::Item>,

self為迭代器自身

S為回傳加起來的結果


product

文件[2]

提出product為將所有元素加起來

    fn product<P>(self) -> P
    where
        Self: Sized,
        P: Product<Self::Item>,

self為迭代器自身

P為乘起來的結果


不管是sum還是product

都可以對Some、Result或是數字本身求和求積


例子

    let nums = [0, 1, 2, 3, 4, 5];
    println!("sum: {}", nums.iter().sum::<i32>());
    println!("product: {}", nums.iter().product::<i32>()); sum: 15 product: 0

第一行數組

第二行與第三行,都是透過iter

將數組放入迭代器中

之後透過sum以及product求和求積

要注意使用sum和product很常要明確指定類型

因此要加上::<i32>

0+1+2+3+4+5 = 15

0*1*2*3*4*5 = 0


而使用Option和Ok也可以

    let nums = [Some(0), Some(1), Some(2), Some(3), Some(4), Some(5), None];
    let res_sum: Option<i32> = nums.iter().cloned().sum();
    match res_sum {
        Some(sum) => println!("Option Sum: {}", sum),
        None => println!("Option Sum: None"),
    }
Option Sum: None

因為數組中有一個None

因此會直接回傳None

Ok也可以像程式碼這樣直接用

    let nums: [Result<i32, &str>; 5] = [Ok(1), Ok(2), Ok(3), Ok(4), Ok(5)];
    let res_product: Result<i32,_> = nums.into_iter().product();
    match res_product {
        Ok(product) => println!("Product: {}", product),
        Err(e) => println!("Error: {}", e),
    } Product: 120

就可以將數組中所有的值乘起來


這兩個程式碼有個小地方不一樣

第一個Option我使用cloned[3]

第二個程式碼我是用into_iter[4]

那是因為在Option和Result使用sum和product

需要得到其所有權

cloned可以把每個元素都clone

而into_iter則是所有權轉移


應用

很多題目都會用到求和求積的方法

這邊有一個CodeWar[5]的題目我覺得蠻有趣的

A Narcissistic Number (or Armstrong Number) is a positive number which is the sum of its own digits, each raised to the power of the number of digits in a given base. In this Kata, we will restrict ourselves to decimal (base 10).

For example, take 153 (3 digits), which is narcissistic:

    1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153

and 1652 (4 digits), which isn't:

    1^4 + 6^4 + 5^4 + 2^4 = 1 + 1296 + 625 + 16 = 1938

這題要找自戀數

簡單來說,假設有個n位數,他需要滿足每一位數的n次方相加後,要等於該數字

例如 153, 1^3 + 5^3 + 3^3 = 153

每個位數的次方要等於該數長度

更詳細可以在參考資料找到

    fn narcissistic(num: u64) -> bool {
        todo!()
    }
    #[cfg(test)]
    mod tests {
        use super::*;

        fn dotest(input: u64, expected: bool) {
            let actual = narcissistic(input);
            assert_eq!(actual, expected, "\nIncorrect answer for n={}\nExpected: {expected}\nActual: {actual}", input)
        }

        #[test]
        fn basic_tests() {
            dotest(   7,  true);
            dotest( 371,  true);
            dotest( 122, false);
            dotest(4887, false);
        }
    }

可以由narcissistic撰寫

並且由下方程式碼測試


解答

一個小思路

假設我可以把每一位數取出來

並且把每位數乘上n次方

再加起來做比較


思路有了直接實作

    fn narcissistic(num: u64) -> bool {
        num == num
        .to_string()
        .chars()
        .map(|c| c.to_digit(10).unwrap() as u64)
        .map(|digit| digit.pow(num.to_string().len() as u32))
        .sum()
    }

第一行做比較,是否加完後的值會等於num

第二行將其轉String並且使用chars放入迭代

因為此時轉成char,因此先使用第一次map轉成數字

再使用第二次map,將每個數字乘上num字數次方

最後加起來


參考資料

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

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

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

[4] https://lageeblog.blogspot.com/2023/11/rust-iterintoiter.html

[5] https://www.codewars.com/kata/5287e858c6b5a9678200083c

[6] https://zh.wikipedia.org/zh-tw/%E6%B0%B4%E4%BB%99%E8%8A%B1%E6%95%B0

0 comments:

張貼留言