[F#] 重複を持たない組合せ(nCm)
こんな感じかな? 数学音痴なので基本式まんまです(^-^; コード:let Combination n m = let rec CC n m = if m = 0 then 1 else let i = CC (n - 1) (m - 1) in (n * i / m) in let i = CC n m in i;;10 C 5 の場合:Combination 10 5 CC 10 5 CC 9 4 CC 8 3 CC 7 2 CC 6 1 CC 5 0 = 1 <-- i = 6 * 1 / 1 = 6 = 7 * 6 / 2 = 21 = 8 * 21 / 3 = 56 = 9 * 56 / 4 = 126 = 10 * 126 / 5 = 252 = 252必ず割り切れるという性質を利用して、毎回割っています。2008/03/19 - 末尾再帰的に書くとこうだ!コード:let Combination (n, m) = let rec CC (i, j, res) = if j > m then res else CC ((i + 1), (j + 1), (i * res / j)) in CC ((n - m + 1), 1, 1);;まちがいない!Labels: F# FSharp
4 Comments:
はじめましてこんばんは。hogehoge! いわれてるいげ太です(^^
内包表記的に書くとこうだ!<マネしてみた
let combination n m =
Seq.fold ( * ) 1 { for i in n..(-1)..(n-m+1) -> i }
/ (Seq.fold ( * ) 1 { for i in m..(-1)..1 -> i });;
By Anonymous, at 12:23 AM
はじめまして!
いげ太さんからコメントもらえるとは驚きです
ブログをよく読ませて頂いてます(^-^
内包表記…さっぱりわかりませんが、直感的に書けるみたいで素敵かもかも!
By BULE!, at 3:23 PM
> 内包表記…さっぱりわかりませんが
ごく簡単にいってしまえば、ループしてリストを作ってるだけです。
(先の例で内包表記が作るのは list ではなく seq ですが)
同様の機能として、C# にはイテレータ ブロックがありますね。
ということで、C# コードに変換してみると以下のようになります。
IEnumerable<int> Numerator(int n, int m)
{
for (var i = n; i >= n-m+1; i--)
yield return i;
}
IEnumerable<int> Denominator(int m)
{
for (var i = m; i >= 1; i--)
yield return i;
}
int Combination(int n, int m)
{
return
Enumerable.Aggregate<int, int>(Numerator(n, m), 1, (x, y) => x * y)
/ Enumerable.Aggregate<int, int>(Denominator(m), 1, (x, y) => x * y);
}
C# では、匿名メソッドで yield が書けないという制約がありますが、
そこ以外はほぼ同じく書けますね。
> 直感的に書けるみたいで素敵かもかも!
実は、先コメントのコードは、もっと簡潔に書けます。
寝ぼけて for in 書いちゃいましたが、範囲演算子の
部分だけで OK でした(^^;
let combination n m =
Seq.fold ( * ) 1 { n..(-1)..(n-m+1) }
/ Seq.fold ( * ) 1 { m..(-1)..1 };;
長文コメント失礼しました。
By Anonymous, at 10:50 AM
なるほど
反復処理をサポートするリストを簡単な記述で作れちゃって、
数学的な表現に近いコーディングを助けるものなんですね。
これは色々なところで活躍しそうだー
丁寧な説明をありがとうございます!
By BULE!, at 12:25 PM
Post a Comment
<< Home