http://projecteuler.net/index.php?section=problems&id=8
文字列は文字の配列らしいです。個々の文字にアクセスするには、
let s = "123" printfn "%c" s.[0] // 1
これを数にするには、intに変換すればコードになるのでそれを用いればよいでしょう。
printfn "%d" (int s.[0] - int '0') // 1
前問と同様にこういう場合にListとSequenceとどちらを用いるべきかがわかりません。Listにはtakeがないし、SequenceにはTailが見当たりません。仕方がないのでListを使いtakeは自作します。
let rec take n list = if n = 0 then [] else if list = [] then [] else list.Head :: (take (n - 1) list.Tail)
次々に5つずつ取り出すにはunfoldを使えばよいでしょう。unfoldはNoneが返ってくるとそこで終わります。簡単な例で、
let range m n = Seq.unfold (fun s -> if s >= n then None else Some((s, s + 1))) m printfn "%A" (range 1 3) // seq [1; 2]
結局、
let s = "73167176531330624919225119674426574742355349194934" + "96983520312774506326239578318016984801869478851843" ... + "71636269561882670428252483600823257530420752963450" let rec take n list = if n = 0 then [] else if list = [] then [] else list.Head :: (take (n - 1) list.Tail) let digits = [ for c in s -> int c - int '0' ] let N = 5 let a = (Seq.unfold (fun s -> if s = [] then None else Some((take N s, s.Tail))) digits) let product list = Seq.fold (fun x y -> x * y) 1 list printfn "%d" (Seq.max (Seq.map product a))
Listを使って書きましたが、Sequenceを使うとどうなるでしょう。よく見ると、Tailの代わりにskipという関数を使えばよいようです。
let digits = seq [ for c in s -> int c - int '0' ] let N = 5 let a = (Seq.unfold (fun s -> if Seq.length s < N then None else Some((Seq.take N s, Seq.skip 1 s))) digits) let product list = Seq.fold (fun x y -> x * y) 1 list printfn "%d" (Seq.max (Seq.map product a))
とても遅いです。skipが遅いのでしょうか。