Hatena::Groupcadr

kozima の日記

2010-11-13

同じ年月は同じグループとしてカウントするコード

00:11

http://cadr.g.hatena.ne.jp/g000001/20101113/1289653556 経由。

ときどきやりたくなってそのたびにこんな感じのコードを書いてる気がします。

(loop with h = (make-hash-table :test 'equal)
  for ym in *year-months* do
  (setf #1=(gethash ym h) (1+ (or #1# 0)))
  finally
  (return (sort (loop for ym being each hash-key of h using (hash-value c)
                  collect (cons ym c))
                #'string> :key #'car)))

hash table でカウントしておいて loop で alist に変換してソート。最初から alist にしておいて cdr を incf していくとかも考えられますが,効率はこっちのほうがよいんじゃないかと思います。

ついでにゴルフだとこんなのも使います。

(let ((yms (mapcar #'intern (sort (copy-seq *year-months*) #'string>))))
  (dolist (ym yms) (set ym (if (eval ym) (1+ (eval ym)) 1)))
  (loop for ym in yms if (eval ym) collect `(,ym .,(eval ym)) do (set ym ())))

hash table の代わりに intern して値セルを使う。リストにするときもすでにリストに入れたかどうかを値セルで管理する。

あんまり短くならなかったけど,データの読み込み時にシンボルとして読んでしまえば mapcar intern のところが消えてもう少し短くなりますね。でも実用的なコードでこんなことをしてはいけません。