「もっとプログラム脳を鍛える数学パズル」_pp.018-020 (code:Ruby) -> Rust

[「もっとプログラマ脳を鍛える数学パズル」](https://www.shoeisha.co.jp/book/detail/9784798153612)をRustで書き直すのは、ボケ防止にちょうど良いかもしれない、と思った。

# 例題2 順列と組み合わせ(pp.018-020)

## Ruby

なんだか書籍p.018のpre2_1.rbは、正しい答えが出てない気がする。
定義からすると、順列のコードは、

```
r.upto(n) do |i|
```

ではない、よな・・・。
ということで、正しい答えが出るコード。

```ruby:ex2.rb
require "test/unit"

def nPr(n, r)
    result = 1
    (n-r+1).upto(n) do |i|
        result *= i
    end
    result
end

def nCr(n,r)
    result = 1
    1.upto(r) do |i|
        result = result * (n - i + 1) / i
    end
    result
end

class NPrTest < Test::Unit::TestCase
    def test_nPr
        assert_equal 1, nPr(1,1), "1P1 should return 1."
        assert_equal 720, nPr(6,6), "6P6 should return 720."
        assert_equal 20, nPr(5,2), "5P2 should return 20."
    end

    def test_nCr
        assert_equal 1, nCr(1,1), "1C1 should return 1."
        assert_equal 1, nCr(6,6), "6C6 should return 1."
        assert_equal 10, nCr(5,2), "5C2 should return 10."
    end
end
```

## Rust

```rust:main.rs
fn main() {
    println!("{n}P{r} = {x}", n = 5, r = 2, x = permutation(5, 2));
    println!("{n}C{r} = {x}", n = 5, r = 2, x = combination(5, 2));
}

pub fn permutation(n: i64, r: i64) -> i64 {
    let mut result = 1;
    for i in (n - r + 1)..=n {
        result *= i;
    }
    return result;
}

pub fn combination(n: i64, r: i64) -> i64 {
    let mut result = 1;
    for i in 1..=r {
        result = result * (n - i + 1) / i;
    }
    return result;
}

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

    #[test]
    fn test_permutation() {
        assert_eq!(permutation(1, 1), 1);
        assert_eq!(permutation(6, 6), 720);
        assert_eq!(permutation(5, 2), 20);
    }

    #[test]
    fn test_combination() {
        assert_eq!(combination(1, 1), 1);
        assert_eq!(combination(6, 6), 1);
        assert_eq!(combination(5, 2), 10);
    }
}
```

ベタ移植。ところで、

```rust
result = result * (n - i + 1) / i;
```

と書くのと、

```rust
result *= (n - i + 1) / i;
```

と書くのは違うのか。テストを書きながら進めてよかった。

「`mut`を使いまくるのはどうなのか」と考えてしまうが、1関数内に閉じている限りは、騒ぐほどのこともないと思う。

## 2020/09/29 追記

簡潔なコード例を頂いた。`permutation2()`と`combination2()`として実験。

```rust:main.rs
fn main() {
    println!("{n}P{r} = {x}", n = 5, r = 2, x = permutation(5, 2));
    println!("{n}C{r} = {x}", n = 5, r = 2, x = combination(5, 2));
}

pub fn permutation(n: i64, r: i64) -> i64 {
    let mut result = 1;
    for i in (n - r + 1)..=n {
        result *= i;
    }
    return result;
}

pub fn combination(n: i64, r: i64) -> i64 {
    let mut result = 1;
    for i in 1..=r {
        result = result * (n - i + 1) / i;
    }
    return result;
}

pub fn permutation2(n: i64, r: i64) -> i64 {
    (n - r + 1..=n).product()
}

pub fn combination2(n: i64, r: i64) -> i64 {
    (1..=r).fold(1, |p, i| p * (n - i + 1) / i)
}

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

    #[test]
    fn test_permutation() {
        assert_eq!(permutation(1, 1), 1);
        assert_eq!(permutation(6, 6), 720);
        assert_eq!(permutation(5, 2), 20);
        assert_eq!(permutation(1,1), permutation2(1,1));
        assert_eq!(permutation(6,6), permutation2(6,6));
        assert_eq!(permutation(5,2), permutation2(5,2));
    }

    #[test]
    fn test_combination() {
        assert_eq!(combination(1, 1), 1);
        assert_eq!(combination(6, 6), 1);
        assert_eq!(combination(5, 2), 10);
        assert_eq!(combination(1, 1), combination2(1,1));
        assert_eq!(combination(6, 6), combination2(6,6));
        assert_eq!(combination(5, 2), combination2(5,2));
    }
}
```

確かに同一の結果になる。コードも分かりやすい。