[topic] 親子のペアからツリーを構築

親子ペア定義群からツリー構造をつくります

・親子ペア定義
※親->子
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)))
; )

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))))

Index

Feed

Other

Link

Pathtraq

loading...