clojure-包含?,conj和recur [英] clojure - contains?, conj and recur

查看:65
本文介绍了clojure-包含?,conj和recur的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写带有recur的函数,以便在遇到重复时立即切断序列( [1 2 3 1 4] 应该返回 [1 2 3] ),这是我的功能:

I'm trying to write a function with recur that cut the sequence as soon as it encounters a repetition ([1 2 3 1 4] should return [1 2 3]), this is my function:

(defn cut-at-repetition [a-seq] 
  (loop[[head & tail] a-seq, coll '()]
    (if (empty? head)
      coll
      (if (contains? coll head)
        coll
        (recur (rest tail) (conj coll head))))))

第一个问题是包含的容器?引发异常,我尝试用 some替换它,但没有成功。第二个问题是 recur 部分,这也会引发异常

The first problem is with the contains? that throws an exception, I tried replacing it with some but with no success. The second problem is in the recur part which will also throw an exception

推荐答案

您犯了几个错误:


  • 您使用过包含吗?在序列上。它仅适用于关联的
    集合。使用 some 代替。

  • 您已经测试了序列的第一个元素( head )表示为空?
    测试整个序列。

  • 使用向量累积答案。 conj 将元素添加到列表的
    前面,从而反转答案。

  • You've used contains? on a sequence. It only works on associative collections. Use some instead.
  • You've tested the first element of the sequence (head) for empty?. Test the whole sequence.
  • Use a vector to accumulate the answer. conj adds elements to the front of a list, reversing the answer.

更正这些,我们得到

(defn cut-at-repetition [a-seq] 
  (loop [[head & tail :as all] a-seq, coll []]
    (if (empty? all)
      coll
      (if (some #(= head %) coll)
        coll
        (recur tail (conj coll head))))))

(cut-at-repetition [1 2 3 1 4])
=> [1 2 3]






以上方法有效,但这很慢,因为它会扫描每个缺少的元素的整个序列。所以最好使用一套。


The above works, but it's slow, since it scans the whole sequence for every absent element. So better use a set.

我们叫函数 take-distinct ,因为它类似于 take-while 。如果我们遵循该先例并使其变得懒惰,则可以这样做:

Let's call the function take-distinct, since it is similar to take-while. If we follow that precedent and make it lazy, we can do it thus:

(defn take-distinct [coll]
  (letfn [(td [seen unseen]
              (lazy-seq
                (when-let [[x & xs] (seq unseen)]
                  (when-not (contains? seen x)
                    (cons x (td (conj seen x) xs))))))]
    (td #{} coll)))

我们得到有限序列的预期结果:

We get the expected results for finite sequences:

(map (juxt identity take-distinct) [[] (range 5) [2 3 2]]
=> ([[] nil] [(0 1 2 3 4) (0 1 2 3 4)] [[2 3 2] (2 3)])

从无穷无尽的结果中获得的需求:

And we can take as much as we need from an endless result:

(take 10 (take-distinct (range)))
=> (0 1 2 3 4 5 6 7 8 9)

我会称呼您渴望的版本 take-distinctv ,在 map -> mapv 上。 d这样做:

I would call your eager version take-distinctv, on the map -> mapv precedent. And I'd do it this way:

(defn take-distinctv [coll]
  (loop [seen-vec [], seen-set #{}, unseen coll]
    (if-let [[x & xs] (seq unseen)]
      (if (contains? seen-set x)
        seen-vec
        (recur (conj seen-vec x) (conj seen-set x) xs))
      seen-vec)))

请注意,我们两次携带可见元素:

Notice that we carry the seen elements twice:


  • 作为向量,返回作为解;

  • 作为一组,以测试其成员资格。

@cfrick评论了三个错误中的两个。

Two of the three mistakes were commented on by @cfrick.

这篇关于clojure-包含?,conj和recur的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆