我需要通过应用以下两个规则将以下输入转换为输出:
(def input
[{:simple1 [:from [:simple1 'ds1]]}
{:simple2 [:from-any [[:simple2 'nope] [:simple2 'ds1]]]}
{:walk1 [:from [:sub1 :sub2 'ds1]]}
{:unaffected [:from [:unaffected 'nope]]}
{:replaced-with-nil [:from [:the-original 'ds1]]}
{:concat1 [:concat [[:simple1 'ds1] [:simple2 'ds1]]]}
{:lookup-word [:lookup [:word 'word :word 'ds1]]}])
(def output
[{:simple1 [:from [:simple1 'ds1]]}
{:simple2 [:from-any [[:simple2 'ds1]]]}
{:walk1 [:from [:sub1 :sub2 'ds1]]}
{:replaced-with-nil [:from [:the-original 'ds1]]}
{:concat1 [:concat [[:simple1 'ds1] [:simple2 'ds1]]]}
{:lookup-word [:lookup [:word 'word :word 'ds1]]}])
我想知道拉链是否可以进行这种转换?
答案 0 :(得分:0)
我建议使用clojure.walk
代替这种常规树转换。修改替换函数可能需要花费一些时间,但它可以很好地处理Clojure数据结构的任何嵌套,在基于拉链的方法中,AFAIK可能会更具挑战性。
我们希望收缩我们的树,所以postwalk
是我的首选。它需要一个函数f
和一个树根,然后遍历树,用(f leaf)
替换每个叶子值,然后用父母和他们的父母等替换根,直到最后替换根。 (prewalk
类似,但是从根向下延伸到树叶,所以当你通过分割树枝来种植树时通常会更自然。)
这里的策略是以某种方式构造一个函数,修剪符合我们的删除标准的任何分支,但返回任何其他值不变。
(ns shrink-tree
(:require [clojure.walk :refer [postwalk]]))
(letfn[(rule-1 [node]
(and (vector? node)
(= 'nope (last node))))
(rule-2 [node]
(and
(map? node)
(not-any? #(and (vector? %) (= 'ds1 (last %)))
(tree-seq vector? seq (-> node vals first)))))
(remove-marked [node]
(if (coll? node)
(into (empty node) (remove (some-fn rule-1 rule-2) node))
node))]
(= output (postwalk remove-marked input)))
;; => true
此处fns rule-1
和rule-2
会尝试将您的规则转换为谓词和remove-marked
:
rule1
或rule2
返回真实的所有成员。要同时检查任何一个,我们将谓词与some-fn
组合在一起。 'ds1
或:from-any
等值的方式。答案 1 :(得分:0)
您可能还想考虑查看specter。它允许您选择和转换任意复杂的结构,从而支持这些类型的转换。