はじめに
初心者プログラマです。
「関数型触ってみよう」だけのモチベーションで少し前からF#で遊んでいます。
とりあえず手元には1~10までやってあるので、そこまで記事にする予定です。
初投稿です。よろしくおねがいします。
ProjectEuler
数学(数字?)の問題をプログラムで解く課題がたくさん置いてあるところです。これです。↓
https://projecteuler.net/
日本語翻訳版wiki↓
http://odz.sakura.ne.jp/projecteuler/
早速やっていきます。
手元でしか動かしていないので、間違いがあったら指摘を頂けると喜びます。
Problem 1
10未満の自然数のうち, 3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり, これらの合計は 23 になる.
同じようにして, 1000 未満の 3 か 5 の倍数になっている数字の合計を求めよ.
let rec sum xs =
match xs with
| [] -> 0
| y::ys -> y + sum ys
let filter pred xs =
let rec inFilter xs =
match xs with
| [] -> []
| y::ys -> if pred y then y::inFilter ys else inFilter ys
inFilter xs
let Problem1 = [1..999] |> filter (fun x->(x%3 = 0)||(x%5 = 0)) |> sum
勉強なので、車輪の再開発はどしどししていきます。
特に言うことはない気がしますが、
再帰で足し算をするやつsumと再帰でlist要素抽出をするやつfilterに[1..999]を突っ込んでいます。
Problem 2
フィボナッチ数列の項は前の2つの項の和である. 最初の2項を 1, 2 とすれば, 最初の10項は以下の通りである.
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
数列の項の値が400万以下の, 偶数値の項の総和を求めよ.
let returnFibList lim =
let rec inReturnFibList ns n0 n1 =
match n1 with
| _ when n1 < 2 -> inReturnFibList [] 1 2
| _ when n1 >= lim -> ns
| _ -> inReturnFibList (ns@[n1]) n1 (n0+n1)
inReturnFibList [] 1 2
let Problem2 = returnFibList 4000000 |> filter (fun x -> x%2 = 0) |> sum
フィボナッチ数列を下から求めましたが、変な事ではないですよね・・・?(不安)
400万まで求めて、またfilter、sumですね。
Cとかばっかりやっていたので、filter関数だけで感動しているフシがあります。
それから、この後も続きますが、勉強した流れからか基本的に継続渡しで再帰を作っています。
Problem 3
13195 の素因数は 5, 7, 13, 29 である.
600851475143 の素因数のうち最大のものを求めよ.
let SieveOfEratosthenes (max:int64) =
let rtMax = (float >> sqrt >> int64 <| max)
let rec inSieveOfEratosthenes ps ns =
match ns with
| [] -> ps
| head::body when head > rtMax -> ps@body
| head::body -> inSieveOfEratosthenes (ps@[head]) (filter (fun x -> (x % head <> 0L)) body)
inSieveOfEratosthenes ([]:int64 list) [2L..max]
let findLargestPrimeFactor (target:int64) =
SieveOfEratosthenes target |> filter (fun (x:int64) -> (target % x = 0L))
let rec max64 (xs:int64 list) =
match xs with
| [] -> 0L
| [y] -> y
| y::ys ->
match ys with
| [z] -> if y > z then max64 [z] else max64 [y]
| z::zs -> if y > z then max64 (y::zs) else max64 (z::zs)
| [] -> 0L
let Problem3 = findLargestPrimeFactor 600851475143L |> max64
SieveOfEratosthenes(エラトステネスのふるい)で素数リストを作って、
対象(600851475143)を割り切れる値(=素因数)抽出して、
そのリストの最大値を選んでいます。
型まわりの書き方がわかっておらず「とりあえず全部int64にするか・・・」などとしてしまっています。
そのためにmax関数もint64用を再開発。恥ずかしい事をしていたらどうしよう。
最大の難所はlet rtMax = (float >> sqrt >> int64 <| max)のくだりでした。
「floatにしてsqrtかけてint64にするのを合成した関数にmaxを渡す」という理解ですが、
正直なところググり知識が元なので、別の形に応用して使っていけるかがまだ怪しいところです。
パイプラインをmax|>にするとエラーになる理由とかがよくわかってないのでたぶんダメですね・・・。
おわり
Problem10まで続きます。(投稿したらリンクを貼りに来ます。)→貼りに来ました
(Problem4~5編)
(Problem6~7編)
(Problem8~10編)
ご指導してくださる方がいらっしゃれば、よろしくお願い致します。