与えられた木から、子→親への対応を作る
via 自分には30分でも難しそうな希ガス > 与えられた木から、子→親への対応を作る
木構造が与えられる。たとえばこんなの: (define *tree* '(Root (Spine (Neck (Head)) (RClavicle (RUpperArm (RLowerArm (RHand)))) (LClavicle (LUpperArm (LLowerArm (LHand))))) (RHip (RUpperLeg (RLowerLeg (RFoot)))) (LHip (LUpperLeg (LLowerLeg (LFoot)))))) つまり、 <tree> := (<name> <tree> ...) という構造。 これから、子→親の対応を表すalistを作る手続きを書け、というもの。結果の例はこんな感じ。 各要素の順序は問わない。 ((LHip . Root) (LUpperLeg . LHip) (LLowerLeg . LUpperLeg) (LFoot . LLowerLeg) ...略) 30分で初級。10分で中級。
よかった。10分かからず解けた。
(define (tree->alist tree) (append-map (lambda (x) (cons (cons (car x) (car tree)) (tree->alist x))) (cdr tree))) (tree->alist *tree*) ; ((Spine . Root) (Neck . Spine) (Head . Neck) ; (RClavicle . Spine) (RUpperArm . RClavicle) (RLowerArm . RUpperArm) (RHand . RLowerArm) ; (LClavicle . Spine) (LUpperArm . LClavicle) (LLowerArm . LUpperArm) (LHand . LLowerArm) ; (RHip . Root) (RUpperLeg . RHip) (RLowerLeg . RUpperLeg) (RFoot . RLowerLeg) ; (LHip . Root) (LUpperLeg . LHip) (LLowerLeg . LUpperLeg) (LFoot . LLowerLeg))
順序が逆になってるって事は、foldで解いてるって事か。
ということでfold版。
(define (tree->alist tree) (fold (lambda (x acc) (cons (cons (car x) (car tree)) (append (tree->alist x) acc))) '() (cdr tree))) (tree->alist *tree*) ; ((LHip . Root) (LUpperLeg . LHip) (LLowerLeg . LUpperLeg) (LFoot . LLowerLeg) ; (RHip . Root) (RUpperLeg . RHip) (RLowerLeg . RUpperLeg) (RFoot . RLowerLeg) ; (Spine . Root) (LClavicle . Spine) (LUpperArm . LClavicle) (LLowerArm . LUpperArm) (LHand . LLowerArm) ; (RClavicle . Spine) (RUpperArm . RClavicle) (RLowerArm . RUpperArm) (RHand . RLowerArm) ; (Neck . Spine) (Head . Neck))
こっちのほうがちと早いな。
回答例を見てみると色々解き方があるようだ。
aconsはgaucheの独自拡張か。MzSchemeにはないみたい。ユーティリティに追加しとこう。
おっと、ココ重要
再帰が身についてるかどうかを見るのに手頃かな。 appendによる無駄も、push!による副作用も嫌う場合、再帰パターンが樹状であっても結果がまっすぐなリストならfoldでつないでゆけることは覚えとくと便利かもしれません。
appendは無駄。foldで繋いでゆける。
書いてみよう。
(define (acons key value seq) (cons (cons key value) seq)) (define (tree->alist tree) (define (each-tree tree acc) (let ((parent (car tree))) (fold (lambda (x a) (acons (car x) parent (each-tree x a))) acc (cdr tree)))) (each-tree tree '()))
Shiroさんの回答例を見ながらちと変数多めで書いてみた。foldを2回書く必要は無いので改造を加えた。
matchがよくわからんなぁ。
深さ優先検索しながらひとつづつ突っ込んでいけばappendする必要は無い。
嫌なこと思いついてしまった・・・
問題:
子→親の対応を表すalistが与えられるので、木構造を作る手続きを書け。各要素の順序は問わない。
ぬはームズイなコレ!!
む・ムズイけどできた。スゲー非効率なのでもうちょっと練り直すか。