首页 > 解决方案 > 如何为redis编写一个模仿`lrem`行为的转换器

问题描述

lrem是一个接受n一个值的命令,从列表中删除该值的第一个n元素。

如何使用传感器编写类似的东西:

(lrem [:a :b :c :b :a] 1 :b) 
=> [:a :c :b :a]

(lrem [:a :b :c :b :a] 2 :b) 
=> [:a :c :a]

我想写一些比这更容易的东西:

(loop [acc 0
       output [] 
       [x & more :as arr] arr]
  (cond (empty? arr) output
        (= count acc) (vec (concat output arr))
        (= value x) (recur (inc acc) output more)
        :else (recur acc (conj output x) more)))

标签: clojure

解决方案


这可以通过结合像filter和之类的转换器的方法来完成distinct,因为您的转换器需要做类似它们的事情:

  1. 从序列中删除项目,例如filter
  2. 知道它被删除了多少项目,所以它可以停止。distinct相似之处在于它必须记住它看到的每一个值。

    (defn lrem [n pred]
      (fn [rf]
        (let [removed (volatile! 0)] ;; keep count of removals
          (fn
            ([] (rf))
            ([result] (rf result))
            ([result input]
             (if (and (< @removed n) (pred input))
               (do (vswap! removed inc) ;; increment removal count
                   result)
               (rf result input)))))))
    
    (into []
          (lrem 3 pos?)
          (range 10))
    ;=> [0 4 5 6 7 8 9]
    

推荐阅读