-
-
Save plaster/4245866 to your computer and use it in GitHub Desktop.
(use 'clojure.set) | |
(defn n-multiples [n end] (set (range 0 end n))) | |
(defn solve [] | |
(apply + (union (n-multiples 3 1000) | |
(n-multiples 5 1000)))) |
distinct
! シーケンスだけでいいんですね!すごいシンプルです。
set
に渡してしまうとどうやらぜんぶ評価されてしまう感じですが、distinct
はどうやらちゃんと遅延してる?
core.clj中の定義を覗いてみてるのですが、lazy-seq
がまだよくわかっていません。
https://github.com/clojure/clojure/blob/372f03e2fa63ff7c3544be82d85e8943e85e640b/src/clj/clojure/core.clj#L4514
あと、コメントありがとうございました。初版はキーワード引数使ってみたかったりとか、余分なのがいろいろありますね。
distinct も大変便利ですが, 集合も直感的で良いと思います.
あ, apply
は, 集合に対しても適用できますので seq
は無くて大丈夫です.
おお、本当にいらないですねseq
。修正しました。ありがとうございます。
そういえば、apply
とreduce
の件で気になってることがあったのでした。私の感覚だと、
apply
=> 要素ぜんぶ評価して渡す
reduce
=> 都度シーケンスから取り出して畳み込む
だったので、どっちも使える状況ならreduce
のほうがいいのでは?と思っていたのです。
でも、どうも試してみた感じ、apply
のときにもちゃんと遅延してるようにみえます。
(defn my-* [& ps]
(loop [ ps ps
p 1
]
(if (nil? ps)
p
(let [[x & ps] ps]
(if (zero? x)
0
(recur ps (* p x)))))))
hoge.core=> (apply my-* (concat (repeat 100000 1) [0] (repeat 1)))
0
だとすると、最終的には必ず全部シーケンスから取り出してしまうのが確定なreduce
よりも、
関数の中で引数使うかどうか選べる apply
のほうがいいのかもしれないですね。
数値のシーケンスの総和に関しては
(reduce + '(1 2 3 4 5)) ; -> (+ (+ (+ (+ 1 2) 3) 4) 5)
(apply + '(1 2 3 4 5)) ; -> (+ 1 2 3 4 5)
なので, clojure の +
がもし二引数関数なら reduce
一択なんですが, そもそも +
自体が可変長引数を受け入れる力があるので, 可変長の要素に対する対応を reduce
で強制するのではなく, +
が持っている機能 (たとえそれが内部的に reduce
と等価だとしても) を使って上げる方が, より高い方の抽象化を使っていることになっていいんじゃないか. というのが私の考えです.
ま, おっしゃっているように, で結局 +
もしくは apply
の動作は自分の好み(遅延性があるかとか)にあっているか? というのも一つの尺度ですよね. 参考になります.
@kohyama のコメントを見る前だったので,なんだか同じようなことも書いていますが,私は (apply + coll)
派ですね. > http://tnoda-clojure.tumblr.com/post/37700304493/apply-and-reduce (@ponkore 版解答のコメントに貼ったのと同じ URL)
@plaster https://gist.github.com/4245866#gistcomment-621381 の apply
/my-*
実験分かりやすくて参考になりました.apply
に渡す関数の作り方の勉強にもなりました.
revision d23e70 を見ています.
初版から大分すっきりしましたね :-)
「割らない」というのはかっこいいですね. 思いつきませんでした.
すばらしい別解だと思います.
集合を使わない書き方を参考まで.