什么是惯用的Clojure从列表中的许多人"删除"单个实例?

Gav*_*mun 16 list clojure

我有一个列表,可能包含比较相等的元素.我想要一个类似的列表,但删除了一个元素.所以从(:a:b:c:b:d)我希望能够"删除" 一个:b得到(:a:c:b:d).

上下文是纸牌游戏中的一手牌,其中有两副标准牌正在进行中,因此可能存在重复的牌但仍然一次玩一张.

我有工作代码,见下文.在Clojure中有更多惯用的方法吗?

(defn remove-one [c left right]
  (if (= right ())
    left
    (if (= c (first right))
      (concat (reverse left) (rest right))
      (remove-one c (cons (first right) left) (rest right)))))

(defn remove-card [c cards]
  (remove-one c () cards))
Run Code Online (Sandbox Code Playgroud)

以下是我不久前得到的Scala答案:什么是惯用的Scala方法从一个不可变的List中"删除"一个元素?

mam*_*ing 24

怎么样:

(let [[n m] (split-with (partial not= :b) [:a :b :c :b :d])] (concat n (rest m)))
Run Code Online (Sandbox Code Playgroud)

将列表拆分为:b然后删除:b并连接两个列表.


ama*_*loy 9

我通常用更高阶的函数解决这些问题split-with,但有人已经这样做了.有时它在更原始的层次上工作更具可读性或更高效,所以这里是原始循环代码的更好版本,使用延迟序列并进行推广以获取删除谓词而不是限制为相等检查:

(defn remove-once [pred coll]
  ((fn inner [coll]
     (lazy-seq
      (when-let [[x & xs] (seq coll)]
        (if (pred x)
          xs
          (cons x (inner xs))))))
   coll))


user> (remove-once #{:b} [:a :b :c :b :d])
(:a :c :b :d)
Run Code Online (Sandbox Code Playgroud)

  • 注意我并不是说它更具可读性,但它更有效率,如果你熟悉HOF,比如`split-with`,需要一些练习和"好"的递归代码,这可能是一种很好的做法. (2认同)