循环遍历向量的向量并从 Clojure 中的向量中删除元素

Loop through vector of vectors and remove element from vector in Clojure

我是 clojure 编程的新手,需要一些代码方面的帮助。我有像下面这样的向量向量,

(def start-pos [[[:fox :goose :corn :you] [:boat] []]])

我想遍历向量并从其中一个内部向量中删除一个元素,例如从 start-pos 中删除“:goose”。

我尝试了下面的代码,但由于某种原因它没有按预期工作,

(map #(disj (set %) :goose) start-pos)

相反,结果是,

(#{[:boat] [] [:fox :goose :corn :you]})

正如你从结果中看到的,内部向量现在是一个集合,是的,原来的顺序被扭曲了,有没有办法删除元素而不打乱向量的原始顺序,也许没有转换它先到一组?我首先选择此转换为集合,因为根据文档 disj 仅适用于集合。

添加:这个 post 与 不相似,因为我的向量嵌套了三个向量。

the internal vectors are now a set

那是因为#(disj (set %) :goose)returns一组的结果。

original order is distorted

集合默认不保留插入顺序,类似于具有超过 8 个键的映射。

I would like to loop through the vector and remove an element from one of the internal vectors, e.g. remove ':goose' from start-pos.

通过谓词从集合中删除元素所需的函数称为 remove,但是...

您要删除的值实际上嵌套在 start-pos 的三个向量深处,因此您需要对每个内部向量进行一次额外的迭代,如果您要删除关键字 [=14],依此类推=] 从每个向量递归。这是使用 clojure.walk:

的借口
(clojure.walk/postwalk
  (fn [v]
    (if (coll? v)
      (into (empty v) (remove #{:goose}) v)
      v))
  start-pos)
=> [[[:fox :corn :you] [:boat] []]]

这会遍历 start-pos 中的每个值,从它找到的任何集合中删除 :goose

这是一种不太灵活的方法,我为了自己的利益(学习 Clojure)做了更多的方法

(update-in
  start-pos
  [0 0]
  #(vec (concat
          (subvec % 0 1)
          (subvec % (inc 1)))))

它手动导航并重构 :goose 级别的关键字,使其在

中没有 :goose

我认为解决这个问题的一些替代方法包括 Spectre 和 Zippers

你也可以为此使用 clojure zipper:

user> (require '[clojure.zip :as z])

user> (loop [curr (z/vector-zip start-pos)]
        (cond (z/end? curr) (z/root curr)
              (= :goose (z/node curr)) (recur (z/remove curr))
              :else (recur (z/next curr))))
;; => [[[:fox :corn :you] [:boat] []]]

另外,仅使用 clojure 的核心函数就可以很容易地做到这一点:

user> (defn remv [pred data]
        (if (vector? data)
          (mapv (partial remv pred) (remove pred data))
          data))
#'user/remv

user> (remv #{:goose} start-pos)
;; => [[[:fox :corn :you] [:boat] []]]