Skip to content

Instantly share code, notes, and snippets.

@ponkore
Created December 7, 2012 13:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ponkore/4233289 to your computer and use it in GitHub Desktop.
Save ponkore/4233289 to your computer and use it in GitHub Desktop.
Project Euler Problem 1
;;; Project Euler Problem 1
;;; http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%201
;;;
;;; 10未満の自然数のうち、3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり、 これらの合計は 23 になる。
;;; 同じようにして、1,000 未満の 3 か 5 の倍数になっている数字の合計を求めよ。
;;; 3 もしくは 5の倍数の場合 true、そうでない場合 false を返す filter 判定用関数
(defn fizz-or-buzz?
"3か5で割り切れるならtrue、そうでないならfalseを返す。"
[n]
(or (zero? (mod n 3)) (zero? (mod n 5))))
(defn problem-1
"Projec Euler Problem#1"
([] (problem-1 1000))
([n] (->> (range 1 n) (filter fizz-or-buzz?) (reduce +))))
;;; Project Euler Problem 1
;;; http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%201
;;;
;;; 10未満の自然数のうち、3 もしくは 5 の倍数になっているものは 3, 5, 6, 9 の4つがあり、 これらの合計は 23 になる。
;;; 同じようにして、1,000 未満の 3 か 5 の倍数になっている数字の合計を求めよ。
;;; iterate で繰り返すことができるよう、一つの引数を取り次へとつながるパラメータを戻り値として返す、
;;; シーケンスジェネレータっぽいやつを作る。
(defn fizzbuzz-seq
[[result n]]
(let [incn (inc n)]
[(or (zero? (mod incn 3)) (zero? (mod incn 5))) (inc n)]))
;;; テスト
;(take 10 (iterate fizzbuzz-seq [false 1]))
;=> ([false 1] [false 2] [true 3] [false 4] [true 5] [true 6] [false 7] [false 8] [true 9] [true 10])
;;; それをフィルタする。良い感じ。
;(->> (take 10 (iterate fizzbuzz-seq [false 1])) (filter first))
;=> ([true 3] [true 5] [true 6] [true 9] [true 10])
;;; 答え
(defn problem-1-2
([] (problem-1-2 1000))
([n] (->> (iterate fizzbuzz-seq [false 1])
(take n)
(filter first)
(map second)
(reduce +))))
@kohyama
Copy link

kohyama commented Dec 9, 2012

解答としては bouzuya さんのコードが文句無し模範解答と思います.

bouzuya さんが突っ込んでいるように, この問題に使うには少々おおげさなところが多いですが,
tnoda さんが言うように, もっと大きな問題で使われるようなイディオムが含まれていて,
参考になります.

コメントや doc-string が, きちんと書いてあるのは良いですね.
私も見習わなくては...

apply +reduce + かは, 宗教戦争になりかねないので,

...敢えて宗教戦争に参加すると :-), この場合は apply + の方が抽象的で良いと思います.

@ponkore
Copy link
Author

ponkore commented Dec 9, 2012

bouzuya さんへ

  • 正確性を欠いていたのはどうやら自分のほうでした。私のようなおっさん世代は、自然数には0は含まないと教えられているのです。bouzuya さんに指摘いただくまで、微塵も疑いませんでした。気分を害されたのならすみません。
  • 自分はこういった場での発言とかでへたを打つことが多いので、気をつけたいと思います。今はメンバーも少ないですが、Clojure コミュニティを広げるため、初心者も入ってきやすくするために、なるべくほんわかした感じで行きましょう。

@plaster
Copy link

plaster commented Dec 9, 2012

初めまして。->> 便利そうですね。私こういうの大好きです。

fizz-or-buz?述語があるとの事前情報があったので、シーケンスをフィルタする解なのだろうと思っていました。
どうやったら「別解」になるかなあなどと思いながら、私も解答つくってみました、、、が、かなりnaiveです。setの練習ですね。
https://gist.github.com/4245866 (ここを見てからだいぶ直したのは秘密です。履歴でばれますが)

あと、bouzuyaさん指摘の 3引数reduce、私もこの挙動が好きです。最初foldという名前で探していたのですが、
reduceのオーバーロード(?)で実現されていたのをみつけてびっくりしました。

@tnoda
Copy link

tnoda commented Dec 11, 2012

@ponkore 少々正確でなくても萎縮せずにどんどんコメントを書ける雰囲気のほうが,初心者には入りやすいと思いますので,お互い,これからどんどん間違えましょう.あとからでもやり直しと修正が効きますから(とフラグを立ててみる).

@plaster 別解ありがとうございます.fold についてはごめんなさい,#mitori_clj の Clojure 1.4.0 なんです.1.5.0 になると Reducers の fold 関数が登場するのですが,それまでは,代わりに reduce を使ってくださいね.

@tnoda
Copy link

tnoda commented Dec 11, 2012

ちなみに私は (apply + coll) 派ですが,この場合は apply で書いても reduce で書いてもどちらでもいいと思います.その理由は,...と書きはじめたら長くなったので別記事にまとめてみました.ご参考まで. > http://tnoda-clojure.tumblr.com/post/37700304493/apply-and-reduce

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment