Skip to content

Instantly share code, notes, and snippets.

@tnoda
Created December 20, 2012 04:04
Show Gist options
  • Save tnoda/4342901 to your computer and use it in GitHub Desktop.
Save tnoda/4342901 to your computer and use it in GitHub Desktop.
#mitori_clj Project Euler Problem 12
(ns tnoda.projecteuler.problem-12
(:use [org.clojars.tnoda.math.prime :only [sieve* prime-factors *prime-array*]]
clojure.test))
(defn- solver*
"Returns the value of the first triangle number to have over x divisors."
[x]
(binding [*prime-array* (sieve*)]
(let [triangle-numbers (reductions + (range))
nd (fn number-of-divisors
[x]
(->> (prime-factors x)
vals
(map inc)
(apply *)))]
(->> triangle-numbers
(drop-while #(>= x (nd %)))
first))))
(def solver (partial solver* 500))
(is (= 28 (solver* 5)))
@tnoda
Copy link
Author

tnoda commented Dec 28, 2012

直感的には、素数列というのは、πなど と同様の定数としてだれかが提供してくれるべきものだと思いますので、Math/Primes みたいに使えるのがいいと思います。 [...]

同じ意見です.理想的には言語組込みの素数列シーケンスがあってもいいかもしれないのですが,それをどのようにして提供するのかというのが,使われかたにもよるので,一つに決めきれないのが難しいところです.

ということで、 僕は、素数列をストーリームとしてしまって、 with-openが使えるようにするの がいいと思います。

with-primes というマクロを作って,その中では,最初の一回だけ sieve して,その素数列を使い回すようにするというのを考えているのですが,どうでしょうか.(with-primes マクロの実体は (binding [*prime-array* (sieve*)] ...) なんですけどね.)

@plaster
Copy link

plaster commented Jan 3, 2013

私も解いてみて、約数の個数を求めるのを (count (filter #(zero? (mod n %)) (range 1 (inc n)))) のnaive実装でいつまでたっても実行が終わらずに、@kohyama さんの指摘どおりしばらくハマっていました。
少しかんがえて素因数分解に落ち着いて、最終的には @tnoda さんのコードとほぼ同じになりました。

tnoda/math/prime.clj 書き方や語彙が参考になります。
別の問題で作っていた素因数分解結果をシーケンスにする関数を、この問題向けにmapにするように書きなおしていたのですが、実はfrequenciesでいいのですね。覚えます。

reductions、こういう関数ないかなあと少し探してはみたのですが、見つけられませんでした。
語彙がもっとほしいです。もしくはもっと上手く探せるようになりたいです。でも、こうやってちょっとずつ覚えていくの楽しいですね。

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