如何在 clojure 中添加或更新列表?

How to add or update a list in clojure?

我有这个功能,不知道怎么实现。我只知道怎么用concat,但是错了,因为它只会加,我还需要update

谁能帮帮我?

这是函数:

(defn update-env 
  [env-global key value]
  (if (and (list? value) (= (first value) '*error*))
    env-global
    (concat env-global (list key value))))

这是我需要的代码 运行: (update-env '(+ add - sub x 1 y 2) 'x 3)

这是它应该给出的结果: (+ 添加 - 子 x 3 y 2)

提前致谢!

您可以将 env-global 表示为哈希映射并使用 assoc 进行更新:

(defn update-env [env-global key value]
  (if (and (list? value)
           (= (first value) '*error*))
    env-global
    (assoc env-global key value)))

(update-env '{+ add - sub x 1 y 2} 'x 3)

或者您可以使用列表并将其转换为散列映射并返回(已编辑):

(defn env->map [env]
  (apply hash-map env))

(defn map->env [m]
  (->> m
       (apply list)
       (apply concat)))

(-> (env->map '(+ add - sub x 1 y 2))
    (update-env 'x 3)
    (map->env))

诀窍是对集合的元素进行成对操作,类似于常见的 lisp plist。你可以编这样的东西:

(defn plist-assoc [key new-val plist]
  (->> plist
       (partition 2)
       (mapcat (fn [[k v]] [k (if (= k key) new-val v)]))))

user> (plist-assoc 'x 3 '(+ add - sub x 1 y 2))
;;=> (+ add - sub x 3 y 2)

user> (plist-assoc 'z 3 '(+ add - sub x 1 y 2))
;;=> (+ add - sub x 1 y 2)

所以你的函数看起来像这样:

(defn update-env [env-global key value]
  (if (and (list? value) (= (first value) '*error*))
    env-global
    (plist-assoc key value env-global)))

user> (update-env '(+ add - sub x 1 y 2) 'x 3)
;;=> (+ add - sub x 3 y 2)

更新 如果你需要更新或插入新值,你可以使用类似这样的东西:

(defn assoc-plist2 [key new-val plist]
  (let [[l r] (->> plist
                   (partition 2)
                   (split-with (comp nil? #{key} first)))]
    (apply concat `(~@l ~[key new-val] ~@(rest r)))))

user> (assoc-plist2 'x 10 '(+ add - sub x 1 y 2))
;;=> (+ add - sub x 10 y 2)

user> (assoc-plist2 'z 10 '(+ add - sub x 1 y 2))
;;=> (+ add - sub x 1 y 2 z 10)