有没有更好的方法来编写这个代码,将一个元素插入clojure中的排序列表?

时间:2014-09-04 14:26:53

标签: clojure

我正在https://iloveponies.github.io/120-hour-epic-sax-marathon/one-function-to-rule-them-all.html上练习练习7。我有一个解决方案,但因为预期的输出是一个列表,我不得不为我的一些输出添加“反向”。这看起来有点笨拙。

这是我的代码:

(defn insert [sorted-seq n]
  (loop [output ()
         my-seq sorted-seq]
    (cond 
     (nil? (first my-seq)) 
       (conj output n)
     (nil? (first (rest my-seq))) 
       (reverse (conj output (first my-seq) n))
     :else
      (if (> (first (rest my-seq)) n (first my-seq))
        (reverse (apply conj output (first my-seq) n (rest my-seq)))
        (recur (conj output (first my-seq)) (rest my-seq))))))

(insert [] 2)      ;=> (2)
(insert [1 3 4] 2) ;=> (1 2 3 4)
(insert [1] 2)     ;=> (1 2)

有没有更好的方法来写这个更高效,而不需要反转输出?此外,前两个条件似乎很笨拙。还有更好的方法吗?

3 个答案:

答案 0 :(得分:3)

@ A.Webb的解决方案是您正在寻找的解决方案,但将此留给未来的访问者。

我认为你略微过分复杂了这个问题。

一般的想法是:

  1. 找到您需要插入元素的网站。
  2. 此时将序列分成两部分。
  3. 连接第一个结果序列,元素,第二个结果序列。
  4. 你可以使用split-with组合1和2,它将序列分成两部分:一部分谓词为真,另一部分为假。

    所以,说起clojure:

    (defn insert [coll n]
       (let [[l r] (split-with #(< % n) coll)]
           (concat l [n] r))
    

答案 1 :(得分:1)

我认为练习的目的是使用递归,而不是产生最惯用的代码。您可以使用向右conj向量的数据结构来避免逆转。

(defn insert [sorted-seq n]
  (loop [s sorted-seq, a []]
    (cond 
      (empty? s)       (conj a n)
      (< (first s) n)  (recur (rest s) (conj a (first s)))
      :else            (apply conj a n s))))

答案 2 :(得分:0)

如果您准备采用适当的递归,您可以使用列表完成此操作:

(defn insert [ss n]
  (if (empty? ss)
    (list n)
    (let [[x & xs] ss]
      (if (< n x)
        (cons n ss)
        (cons x (insert xs n))))))
  • 如果您希望它长时间工作,请将身体裹在lazy-seq中 没有吹栈的序列。
  • 它仍然比A. Webb's solution慢得多。