Skip to content

Instantly share code, notes, and snippets.

@bouzuya
Created January 4, 2013 09:04
Show Gist options
  • Save bouzuya/4451081 to your computer and use it in GitHub Desktop.
Save bouzuya/4451081 to your computer and use it in GitHub Desktop.
;;; Project Euler #22
;;; http://projecteuler.net/problem=22
;;; http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2022
; [org.clojure/data.csv "0.1.2"]
(require '[clojure.test :refer [deftest is]]
'[clojure.data.csv :as csv])
(defn char-score
[c]
(- (Character/getNumericValue c) 9))
(defn str-score
[s]
(apply + (map char-score s)))
(defn problem-22
([] (problem-22 "names.txt"))
([file]
(let [names (first (csv/read-csv (slurp file)))
sorted (sort names)
scores (map str-score sorted)]
(apply +
(map-indexed
(fn [idx score]
(* (inc idx) score)) scores)))))
(deftest char-score-test
(is (= (char-score \C) 3))
(is (= (char-score \O) 15))
(is (= (char-score \L) 12))
(is (= (char-score \I) 9))
(is (= (char-score \N) 14)))
(deftest str-score-test
(is (= (str-score "COLIN") 53))
(is (= (str-score "YUKIHO") 89)))
(deftest problem-22-test
(is (= (problem-22) 871198282)))
@bouzuya
Copy link
Author

bouzuya commented Jan 4, 2013

解説

ファイルを読み、並び替えて、スコアを計算する問題。以下、解説とか。

  • ファイルの読み込みには slurp を使いました。手抜きかつ富豪的に。
  • CSV の解釈には最近知った clojure.data.csv を使いました。
  • clojure.data.* には clojure.data.json などもあるみたいですね。使えるものは使いましょう。
  • 改行がない CSV ですし、イレギュラーなデータもないので、前からファイルをなめるのも良いのかもしれません。
  • 文字・文字列のスコア計算はどこかで見たような気がするので割愛。
  • map-indexed を使っています。動きは map に似ていますが、 indexitem とが渡されます。便利ですね。
  • map-indexedindex は 0 origin なので inc しています。

@tnoda
Copy link

tnoda commented Jan 5, 2013

clojure.data.csv 初めて見ました.Java の CSV ライブラリもこれといって定番の OSS がないですし,これは便利ですね.

前に自分で解いてみたときには CSV ライブラリを使ってなかったと思い,ソースコードを引っ張り出してきてみると,

(def ^:private names
  (delay
   (read-string (str \[ (slurp *in*) \]))))

なことをしていました.手抜きさ加減では @bouzuya には負けていないと思います :-)

@kohyama
Copy link

kohyama commented Jan 7, 2013

いつも必要十分, 簡潔, 明解なコードとテストでとても素敵です. 見習いたいです.

map-indexed いいですね.
手動で (map vector foo (range)) みたいにしてた気がします. 今度からこれを使います.

clojure.data.csv も知りませんでした. 紹介ありがとうございます.
こちらは今度からと言わず, 既存コードもこれを使うように直そうと思います.

@bouzuya
Copy link
Author

bouzuya commented Jan 7, 2013

@tnoda
良い手抜きですね。"xxx","yyy" で綺麗にならんでますもんね。

@kohyama
map-indexed はなくてもいいけど、あったらあったで困らないあたりが好きです。

変数が多いのをすこし気にしています。 @tnoda のコードはいつも -> などがうまく使われていてすっきりしている気がします。

@emanon001
Copy link

clojure.data.csv 知りませんでした。よいですね。
最初 (clojure.string/split (slurp "names.txt") #",") でよいのでは、と思いましたが、名前が "で囲まれていることを忘れていました。

@tnoda のコードでは、read-string による S式の文字列表現のデシリアライズが行なわれていますが、こちらも便利な機能ですね。勉強になります。
Clojure だけで完結する処理ならば、中間データとして JSON や XML ではなく S式を用いるのは、選択肢として大いにありだと思います。

@tnoda
Copy link

tnoda commented Jan 9, 2013

Clojure だけで完結する処理ならば、中間データとして JSON や XML ではなく S式を用いるのは、選択肢として大いにありだと思います。

edn ですね.JSON よりも速いので,Clojure で使うだけなら迷うことはないですね.参考→ http://tnoda-clojure.tumblr.com/post/28499910150/collection-literals-instead-of-json (edn が発表される前に書いたもの)

@kohyama
Copy link

kohyama commented Jan 10, 2013

@tnoda さん. edn 知らなかったです. 御ブログもとても参考になります.

@ypsilon-takai
Copy link

変数が多いのをすこし気にしています。 @tnoda のコードはいつも -> などがうまく使われていてすっきりしている気がします。

-> などを使うと意図が見えにくくなるという欠点もありますよね。複数回使うからでなくて、説明のために変数に束縛するというのもありだと思います。

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