木、子→親
Schemeはまだまともに書けないのでGroovyで挑戦。
Tree = ['Root', ['Spine', ['Neck', ['Head']], ['RClavicle', ['RUpperArm', ['RLowerArm', ['RHand']]]], ['LClavicle', ['LUpperArm', ['LLowerArm', ['LHand']]]]], ['RHip', ['RUpperLeg', ['RLowerLeg', ['RFoot']]]], ['LHip', ['LUpperLeg', ['LLowerLeg', ['LFoot']]]]] f1 = { def alist = [], f (f = { def p = it[0] it[1] && it[1..-1].each{ alist << [f(it), p] } p }) it alist } print f1(Tree)
> groovy tpc.groovy [["Head", "Neck"], ["Neck", "Spine"], ["RHand", "RLowerArm"], ["RLowerArm", "RUp perArm"], ["RUpperArm", "RClavicle"], ["RClavicle", "Spine"], ["LHand", "LLowerA rm"], ["LLowerArm", "LUpperArm"], ["LUpperArm", "LClavicle"], ["LClavicle", "Spi ne"], ["Spine", "Root"], ["RFoot", "RLowerLeg"], ["RLowerLeg", "RUpperLeg"], ["R UpperLeg", "RHip"], ["RHip", "Root"], ["LFoot", "LLowerLeg"], ["LLowerLeg", "LUp perLeg"], ["LUpperLeg", "LHip"], ["LHip", "Root"]]
def の挙動にはまって10分では解けなかった。
> groovy -e "def a = { print a }; a()" Caught: groovy.lang.MissingPropertyException: No such property: a for class...
上のように書くとクロージャ生成の後で変数定義が成されるため,自身の名前を参照出来ず再帰にならないのだ。*1。
で,他の人の解答例を眺めていたらGroovyでもパターンマッチもどきが出来ることを思い出した。sumimさんにならってalistをMapに置き換えつつ書き直し。
f2 = { def pmap = [:], f (f = { name, ...tree -> tree.each{ pmap[f(*it)] = name } name })(*it) pmap }
+
カコイイ。こういうの見るとLisp覚えねばと思う。Groovyに訳すと…
class foo { static Map bar(String n, List t, ...ts){ [(t[0]): n, *: bar(*t), *: bar(n, *ts)] } static Map bar(List t){ bar(*t) } static Map bar(_){ [:] } } print foo.bar(Tree)
動くことは動くが冗長な感じ。
*1:JSは事前に var の評価をしておくので「var f = function()... 」が期待通りに動作する。