Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Map Clojure:在中更新,但使用通配符和路径跟踪_Map_Clojure_Tree - Fatal编程技术网

Map Clojure:在中更新,但使用通配符和路径跟踪

Map Clojure:在中更新,但使用通配符和路径跟踪,map,clojure,tree,Map,Clojure,Tree,我正在尝试更新由嵌套映射和序列组成的结构中的值,但是updatein无法工作,因为我希望允许使用通配符。我的手动方法导致我使用丑陋的、大的、嵌套的for和到{}调用中。我最终制作了一个函数,它采用了结构、一个类似选择器的序列和一个更新函数 (defn更新中的每个 ([o[头部和尾部:作为路径]f] (更新o路径f[]中的每个路径) ([o[头和尾:作为路径]f当前路径] (续) (空?路径)(f为当前路径) (相同?*头) (续) (地图?o) (进入{}(代表[[k v]o] [k(更新v t

我正在尝试更新由嵌套映射和序列组成的结构中的值,但是
updatein
无法工作,因为我希望允许使用通配符。我的手动方法导致我使用丑陋的、大的、嵌套的
for
到{}
调用中。我最终制作了一个函数,它采用了结构、一个类似选择器的序列和一个更新函数

(defn更新中的每个
([o[头部和尾部:作为路径]f]
(更新o路径f[]中的每个路径)
([o[头和尾:作为路径]f当前路径]
(续)
(空?路径)(f为当前路径)
(相同?*头)
(续)
(地图?o)
(进入{}(代表[[k v]o]
[k(更新v tail f中的每个(连接当前路径k))])
:else(对于[iv](映射索引向量o)]
(更新v尾f中的每个(连接当前路径i)))
:其他(助理署长)
(更新(获取o头)尾部f中的每个(联合当前路径头‘‘‘‘‘‘‘)’)
这使我可以简化以下更新

(def sample{“TR”[{:geometry{:ID12{:buffer 22}}
{:geometry{:ID13{:buffer 33}
:ID14{:buffer 55}}
{:geometry{:ID13{:buffer 44}}]
“BR”[{:geometry{:ID13{:buffer 22}
:ID18{:buffer 11}}
{:geometry{:ID13{:buffer 33}}
{:geometry{:ID13{:buffer 44}}]})
(更新样本[**:geometry*:buffer]中的每个样本)
(fn[buf路径](inc buf)))
显然,这有一个堆栈溢出问题,具有深度嵌套结构;虽然我还远没有达到这个目标,但拥有一个健壮的解决方案会很好。有人能提出一个更简单/更快/更优雅的解决方案吗?这可以通过减速器/传感器实现吗


更新要求更新函数也获取其更新的值的完整路径。

中的更新
与您创建的函数具有完全相同的签名,并且它执行的操作几乎完全相同。有两个区别:它不允许在“路径”中使用通配符,也不向update函数传递中间路径

中的更新添加通配符

我把这个改编自《圣经》

现在,这两条线产生相同的结果:

(update-in-* sample [* * :geometry * :buffer] (fn [buf] (inc buf)))
(update-each-in sample [* * :geometry * :buffer] (fn [buf path] (inc buf)))
(update-in-* sample [* * :geometry * :buffer] (fn [path val] (inc val)))
(update-each-in sample [* * :geometry * :buffer] (fn [buf path] (inc buf)))
我对中的
更新所做的更改只是通过检查通配符进行分支。如果遇到通配符,则必须修改该级别的每个子节点。我使用
reduce
来保存集合的累积更新

另外,出于健壮性的考虑,我会尝试对通配符使用
*
以外的内容。它可能作为映射中的键出现

将路径跟踪添加到
更新中

如果需要更新函数接收完整路径,那么我只需再次修改
updatein
。函数签名会更改,并添加
(conj p k)
,但仅此而已

(defn update-in-*
    [m ks f & args] (apply update-in-*-with-path [] m ks f args))

(defn- update-in-*-with-path
    [p m [k & ks] f & args]
        (if (identical? k *)
            (let [idx (if (map? m) (keys m) (range (count m)))]
                (if ks
                    (reduce #(assoc % %2 (apply update-in-*-with-path (conj p k) (get % %2) ks f args))
                            m
                            idx)
                    (reduce #(assoc % %2 (apply f (conj p k) (get % %2) args))
                            m
                            idx)))
            (if ks
                (assoc m k (apply update-in-*-with-path (conj p k) (get m k) ks f args))
                (assoc m k (apply f (conj p k) (get m k) args)))))
现在,这两条线产生相同的结果:

(update-in-* sample [* * :geometry * :buffer] (fn [buf] (inc buf)))
(update-each-in sample [* * :geometry * :buffer] (fn [buf path] (inc buf)))
(update-in-* sample [* * :geometry * :buffer] (fn [path val] (inc val)))
(update-each-in sample [* * :geometry * :buffer] (fn [buf path] (inc buf)))

这比你原来的解决方案好吗?我不知道。我喜欢它,因为它是以
中的
更新为模型的,其他人对
中的
更新的考虑可能比我自己更仔细。

你能为你的问题提供示例预期输出吗?@Symfrog你可以评估整个示例,它会给你预期输出。非常好的尝试,我根本没有想到要查看
源代码中的
更新。然而。如果任何嵌套结构不是
iasocialive
,则这不起作用,即输入数据通常是生成惰性序列的函数的产物,而不是仅由映射和向量组成的手动编码
sample
。我的原始版本确实有效,因为它对
表单使用了
。它实际上教会了我,
core
中的
更新在
中不适用于惰性序列。实际上,如果
path
中的最后一个元素是惰性序列的整数索引,我的也会崩溃。因为它也在使用
assoc
。@skrat然后你可以继续通过编写你自己的适用于所有序列的assoc来进行调整,并根据你是否正在查看地图等使用get/nth。我不知道你的用例,但你可能想重新考虑你对数据结构的选择。看见