如何在Clojure中删除vector中的顺序匹配?

And*_*rew 7 algorithm vector clojure

假设我有一个向量["a" "b" "c" "a" "a" "b"].如果给定一个序列["a" "b"],我该如何删除该序列的所有实例(按顺序)?在这里,结果就是["c" "a"].

Ole*_*Cat 6

如果事先知道需要删除的序列,则core.match可能对您的任务有用:

(require '[clojure.core.match :refer [match]])

(defn remove-patterns [seq]
  (match seq
    ["a" "b" & xs] (remove-patterns xs)
    [x & xs] (cons x (remove-patterns xs))
    [] ()))


(remove-patterns ["a" "b" "c" "a" "a" "b"]) ;; => ("c" "a")
Run Code Online (Sandbox Code Playgroud)


Tim*_*ley 5

简短的回答是将其视为字符串并执行正则表达式删除:

(defn remove-ab [v]
  (mapv str (clojure.string/replace (apply str v) #"ab" "")))

(remove-ab ["a" "b" "c" "a" "a" "b"])
=> ["c" "a"]
Run Code Online (Sandbox Code Playgroud)

很长的答案是通过迭代序列,识别匹配并返回没有它们的序列来实现自己的正则表达式状态机.

Automat可以帮助您制作自己的低级正则表达式状态机:https: //github.com/ztellman/automat

Instaparse可用于制作丰富的语法:https: //github.com/Engelberg/instaparse

你真的不需要一个用于这么小的匹配的库,你可以将它实现为循环:

(defn remove-ab [v]
  (loop [[c & remaining] v
         acc []
         saw-a false]
    (cond
     (nil? c) (if saw-a (conj acc "a") acc) ;; terminate
     (and (= "b" c) saw-a) (recur remaining acc false)  ;; ignore ab
     (= "a" c) (recur remaining (if saw-a (conj acc "a") acc) true) ;; got a
     (and (not= "b" c) saw-a) (recur remaining (conj (conj acc "a") c) false) ;; keep ac
     :else (recur remaining (conj acc c) false)))) ;; add c
Run Code Online (Sandbox Code Playgroud)

但是,正确处理所有条件可能会非常棘手......因此正式的正则表达式或状态机是有利的.

或者递归定义:

(defn remove-ab [[x y & rest]]
  (cond
   (and (= x "a") (= y "b")) (recur rest)
   (nil? x) ()
   (nil? y) [x]
   :else (cons x (remove-ab (cons y rest)))))
Run Code Online (Sandbox Code Playgroud)