[topic] 親子のペアからツリーを構築
Posted feedbacks - Common Lisp
親子ペア定義群からツリー構造をつくります
・親子ペア定義
※親->子
A->B
B->C
C->D
C->E
A->F
D->X
Y->Z
Z->C
・ツリー
A
->B
->C
->D
->X
->E
->F
Y
->Z
->C
->D
->X
->E
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | ; 親子ペア定義
(setf pair-lst '((a b)
(b c)
(c d)
(c e)
(a f)
(d x)
(y z)
(z c)
))
;; 同一の親を持つペアをマージする
;; ex) ((p1 c1) (p1 c2) (p2 c3) (p2 c4)) -> ((p1 c1 c2) (p2 c3 c4))
(defun gen-fmly-lst (plst)
(defun merge-lst (frst rst)
(if (null rst)
frst
(if (eq (car frst) (caar rst))
(merge-lst (append frst (cdar rst)) (cdr rst))
(merge-lst frst (cdr rst)))))
(labels ((rec (lst acc)
(if (null lst)
acc
(if (member (caar lst) acc :key #'car)
(rec (cdr lst) acc)
(rec (cdr lst) (cons (merge-lst (car lst) (cdr lst)) acc))))))
(rec plst nil)))
;; fmlyのリストからツリーを生成する
(defun gen-fmly-tr (fmly-lst)
(labels ((rec (flst acc)
(if (null flst)
acc
; hook前のfmlyをhook後のfmly(n次元リスト)に置き換えて処理をする
(let* ((nD-fmly (car (member (caar flst) acc :key #'car)))
(othr (other nD-fmly acc)))
; fmlyをhook処理し、一箇所もhookできなかったらfmlyをそのままaccに加える
(if (equal othr (hook nD-fmly othr))
(rec (cdr flst) (cons nD-fmly othr))
(rec (cdr flst) (hook nD-fmly othr)))))))
(rec fmly-lst fmly-lst)))
;; リストからobjを除いたリストを取得する
(defmacro other (obj lst)
`(remove-if #'(lambda (x) (equal ,obj x)) ,lst))
;; リストのcarと一致するatomをツリーの中で見つけた場合、該当atomをリストで置き換える
;; ex) (hook '(a x) '(a (b a) (c (d a)))) -> ((a x) (b (a x)) (c (d (a x))))
(defun hook (lst tree)
(cond ((eq (car lst) tree) lst)
((atom tree) tree)
(t (cons (hook lst (car tree))
(hook lst (cdr tree))))))
(defun main ()
(gen-fmly-tr (gen-fmly-lst pair-lst)))
; 実行すると、下記の構造が得られる
; ((A (B (C (D X) E)) F) (Y (Z (C (D X) E))))
; インデントすると
;((A
; (B
; (C
; (D
; X)
; E))
; F)
; (Y
; (Z
; (C
; (D
; X)
; E)))
; )
|
>(setf env (gen-family-relation pair-lst '())) ((Z C)(Y Z)(D X)(C D E)(B C)(A B F)) >(query 'A env) (A (B (C (D X) E)) F) >(query 'Y env) (Y (Z (C (D X) E)))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | (setf pair-lst '((a b)
(b c)
(c d)
(c e)
(a f)
(d x)
(y z)
(z c) ))
(defun gen-family-relation (list env)
(let ( node result )
(dolist (x list result)
(setf node (assoc (car x) env))
(if node
(setf (cdr node) (append (cdr node) (cdr x)))
(push x env) )
(setf result env) )))
(defun query (s env)
(let ((node (assoc s env)))
(if node
(cons (car node)(mapcar #'(lambda (x)(query x env)) (cdr node)))
s)))
|
とりあえず構造体とハッシュをつかって。treeのユーティリティは ANSI Common Lispにとりあげられていたよ。 DOKAKU178> (maphash #'(lambda(k v) (print-tree k)) *population*) NIL => A => (F B) (A) => B => (C) (Z B) => C => (E D) (C) => D => (X) (C) => E => NIL (A) => F => NIL (D) => X => NIL NIL => Y => (Z) (Y) => Z => (C)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | (defpackage :dokaku178
(:use :common-lisp))
(in-package :dokaku178)
(defvar *population* (make-hash-table))
(defstruct tree
id children parents)
(defun get-node (key)
(multiple-value-bind (hash-value flag) (gethash key *population*)
(if (null flag)
(setf (gethash key *population*) (make-tree :id key
:parents nil
:children nil))
hash-value)))
(defun set-node (pair-list)
(let* ((parent (car pair-list))
(child (cdr pair-list))
(parent-node (get-node parent))
(child-node (get-node child)))
(pushnew parent (tree-parents child-node))
(pushnew child (tree-children parent-node))))
(defun get-origins ()
(let ((origins nil))
(maphash #'(lambda(k v)
(if (null (tree-parents v))
(pushnew k origins))) *population*)
origins))
(defun print-tree (id)
(let ((id (gethash id *population*)))
(format t "~a => ~a => ~a ~%" (tree-parents id)
(tree-id id)
(tree-children id))))
(defun main()
(let ((pair-lst
'((a . b)(b . c)(c . d)(c . e)
(a . f)(d . x)(y . z)(z . c))))
(loop for n in pair-lst do
(set-node n))))
|



hu2 #6327() [ Common Lisp ] Rating0/0=0.00
親子ペア定義群からツリー構造をつくります ・親子ペア定義 ※親->子 A->B B->C C->D C->E A->F D->X Y->Z Z->C ・ツリー A ->B ->C ->D ->X ->E ->F Y ->Z ->C ->D ->X ->E; 親子ペア定義 (setf pair-lst '((a b) (b c) (c d) (c e) (a f) (d x) (y z) (z c) )) ;; 同一の親を持つペアをマージする ;; ex) ((p1 c1) (p1 c2) (p2 c3) (p2 c4)) -> ((p1 c1 c2) (p2 c3 c4)) (defun gen-fmly-lst (plst) (defun merge-lst (frst rst) (if (null rst) frst (if (eq (car frst) (caar rst)) (merge-lst (append frst (cdar rst)) (cdr rst)) (merge-lst frst (cdr rst))))) (labels ((rec (lst acc) (if (null lst) acc (if (member (caar lst) acc :key #'car) (rec (cdr lst) acc) (rec (cdr lst) (cons (merge-lst (car lst) (cdr lst)) acc)))))) (rec plst nil))) ;; fmlyのリストからツリーを生成する (defun gen-fmly-tr (fmly-lst) (labels ((rec (flst acc) (if (null flst) acc ; hook前のfmlyをhook後のfmly(n次元リスト)に置き換えて処理をする (let* ((nD-fmly (car (member (caar flst) acc :key #'car))) (othr (other nD-fmly acc))) ; fmlyをhook処理し、一箇所もhookできなかったらfmlyをそのままaccに加える (if (equal othr (hook nD-fmly othr)) (rec (cdr flst) (cons nD-fmly othr)) (rec (cdr flst) (hook nD-fmly othr))))))) (rec fmly-lst fmly-lst))) ;; リストからobjを除いたリストを取得する (defmacro other (obj lst) `(remove-if #'(lambda (x) (equal ,obj x)) ,lst)) ;; リストのcarと一致するatomをツリーの中で見つけた場合、該当atomをリストで置き換える ;; ex) (hook '(a x) '(a (b a) (c (d a)))) -> ((a x) (b (a x)) (c (d (a x)))) (defun hook (lst tree) (cond ((eq (car lst) tree) lst) ((atom tree) tree) (t (cons (hook lst (car tree)) (hook lst (cdr tree)))))) (defun main () (gen-fmly-tr (gen-fmly-lst pair-lst))) ; 実行すると、下記の構造が得られる ; ((A (B (C (D X) E)) F) (Y (Z (C (D X) E)))) ; インデントすると ;((A ; (B ; (C ; (D ; X) ; E)) ; F) ; (Y ; (Z ; (C ; (D ; X) ; E))) ; )Rating0/0=0.00-0+
[ reply ]