データが扱える人を探せ!

JAVA5.0でGO!! | プログラミングに自信があるやつこい!!


というわけで、気楽に作ってみた。topcoderからの出題なのね。

(defun who-can-see (usrs ability needs)
  (let ((l (mapcar (lambda (x y) (list x (split-string y #\SPC))) usrs ability)))
    (dolist (a needs)
      (setq l (remove-if-not (lambda (x) (find a x :test 'string=)) l :key 'cadr)))
    (mapcar 'car l)))

問題読んでからテスト終えるまで12分15秒。問題読むのに5分くらいかかったからちょっと時間オーバー。テストケースが複雑なんだって。

(who-can-see '("joe" "nick" "ted")
               '("clients products" "products orders" "clients orders")
               '("products" "clients"))
|("joe")
(who-can-see '("kathy" "john" "dan" "steve" "cheryl" "tony")
               '("users data" "data orders" "users permissions" "system users controls" "default" "admin users")
               '("users"))
|("kathy" "dan" "steve" "tony")
(who-can-see '("jim" "scott" "barbara")
               '("users order products" "products shipping" "tracking products orders")
               '("admin"))
| nil

引数の通りだと扱いにくいので、人と技能をまとめる。技能は予め要求と同じ形に直しておく。そうしたら要求1つごとに技能から探して、持ってない人から除去。残っている人を出力。という感じで作った。cadrがcdrで良いかと思い違ったので、そこを直すのに少し手間取ったり。


一応、よりエレガント(?)にletもdolistもsetqも省いたバージョン。こうなれば純粋関数型である(多分)。一つの関数にしたけど、実際は各段階で分けた方が分かりやすい。そこら辺はhaskellのwhereみたいに書けると格好いいのだが。

(defun who-can-see (usrs ability needs)
  (mapcar 'car
          (reduce (lambda (l a) (remove-if-not (lambda (x) (find a x :test 'string=)) l :key 'cdr))
                  (cons (mapcar (lambda (x y) (cons x (split-string y #\SPC))) usrs ability)
                        needs))))

見やすいように分割した例。どこでデータに手を加えるかで分割の仕方が色々考えられる。読みやすく書けるようになるにはかなりの知識と経験が必要だ。

(defun who-can-see (usrs ability needs)
  (mapcar 'car (who-can-see-sub (mapcar 'wcs-merge usrs ability) needs)))

(defun who-can-see-sub (data needs)
  (reduce 'wcs-remove (cons data needs)))

(defun wcs-remove (l a)
  (remove-if-not (lambda (x) (find a x :test 'string=)) l :key 'cdr))

(defun wcs-merge (x y)
  (cons x (split-string y #\SPC)))

(who-can-see '("joe" "nick" "ted")
'("clients products" "products orders" "clients orders")
'("products" "clients"))


それにしても、こういう形式のデータはlispにも向いてないし、オブジェクト指向にもなってない気がするけど、何を想定した例題なんだろう。簡単な例題だから良いのか。